Commit graph

29 commits

Author SHA1 Message Date
John Mizerek
07abcee2fd Create kitchen task on order submission for KDS display
submitCash.php had no task creation — cash orders were invisible to KDS.
submit.php also lacked it (tab orders never hit webhook.php).
Both now create "Prepare Order #X for Table" task at StatusID=1.
submit.php includes duplicate guard since webhook.php also creates tasks
for card payments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:02:02 -07:00
John Mizerek
5d9be247c8 Add beacons/lookupByMac.php and beacons/wipe.php endpoints
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 19:13:21 -07:00
John Mizerek
04d09cfc4e Fix item prices returning as strings instead of floats in JSON
MySQL PDO returns DECIMAL/FLOAT columns as strings, causing json_encode
to emit them as JSON strings ("9.99") instead of numbers (9.99).
Android's Gson Map parsing fails the as? Number cast on strings,
defaulting to 0.0. Cast Price to (float) before building the response.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 17:24:57 -07:00
John Mizerek
8b54145d9d Add IsServiceBell flag to task types
Only Call Staff, Chat With Staff, and Pay With Cash should appear
on the customer service bell. New column distinguishes service bell
items from internal task types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 16:52:23 -07:00
John Mizerek
5761ed3e88 Standardize UUID format: generateUUID() now returns unhyphenated 32-char hex
- Remove vsprintf hyphenation from generateUUID() in helpers.php
- Remove redundant str_replace('-', '', ...) wrappers in callers
- Fix grants/create, tabs/open, orders/getOrCreateCart which were storing hyphenated UUIDs
- Cast prices to float in getForBuilder.php
- Uppercase auth response keys (TOKEN, USERID, FIRSTNAME)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 16:43:02 -07:00
John Mizerek
bb03cb0533 Cast prices to float in getForBuilder.php
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 15:06:42 -07:00
John Mizerek
6ec5f812e1 Fix: restore cd and stderr redirect for platform-images shell_exec
Got reverted during earlier merge conflict resolution. Without cd,
node can't find modules. Without stderr redirect, log lines corrupt
the JSON output causing json_decode to fail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 10:19:31 -07:00
John Mizerek
4c5d8b07dc Revert og:image header extraction — header is manual upload
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 09:46:21 -07:00
John Mizerek
d7cd6774c7 Extract og:image as header during wizard discovery
- analyzeMenuUrl.php: Extract og:image and JSON-LD image during discovery, return as headerImageUrl
- downloadImages.php: Add User-Agent header, detect image format from content-type/magic bytes, update HeaderImageExtension in DB

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 09:36:43 -07:00
John Mizerek
add3842db3 Return priceMap from platform_images mode
order.online embeds displayPrice alongside images — now extracted and
returned so items missing prices from image-based menus get filled in.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 02:36:01 -07:00
John Mizerek
436f83d67e Fix: use queryTimed instead of undefined $pdo for ImageExtension update
$pdo doesn't exist in this file — all DB queries use queryTimed/queryOne
from helpers.php.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 02:08:26 -07:00
John Mizerek
5d34d8378b Fix: set ImageExtension after downloading item images in saveWizard
downloadItemImage() saved files to disk but never updated the DB column,
so items appeared to have no images despite files existing on disk.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:57:39 -07:00
John Mizerek
280394f5e0 Move app from /opt to /var/www/payfrit-api (standard Linux web dir)
- Moved directory on both dev and biz servers
- Updated nginx configs on both servers
- Added appRoot() helper, uploadsRoot() uses it
- No more hardcoded /opt/payfrit-api paths in codebase

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:32:55 -07:00
John Mizerek
aa986507fd Remove all Lucee references — uploads now live under /opt/payfrit-api
- Moved uploads from Lucee webroot to /opt/payfrit-api/uploads/
- Updated nginx on both dev and biz to alias /uploads/ to new path
- Replaced luceeWebroot() with uploadsRoot() helper
- Temp files now use /opt/payfrit-api/temp/
- No more /opt/lucee or /var/www/biz.payfrit.com references

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:26:52 -07:00
John Mizerek
28d86ba6e5 Fix production webroot path — both servers use /opt/lucee/tomcat/webapps/ROOT
Added luceeWebroot() helper to avoid repeating the path. The previous
fix incorrectly used /var/www/biz.payfrit.com for production, but both
dev and biz use the same Lucee webroot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:19:10 -07:00
John Mizerek
4a4a098551 Fix upload paths to use Lucee webroot and accept uppercase OTP keys
Upload endpoints were saving files to PHP's DOCUMENT_ROOT instead of
the Lucee webroot where the Android app loads them from. Also fix
verifyLoginOTP and verifyOTP to accept both UUID/OTP and uuid/otp keys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:04:27 -07:00
John Mizerek
3d9084d848 Add platform_images mode with stealth Playwright for order.online
- Stealth Playwright bypasses Cloudflare bot protection
- Multiple selector strategies for menu item cards
- Fuzzy name matching (exact, normalized, partial)
- Background-image extraction as fallback
- Script auto-created at /opt/playwright/platform-images.js

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 20:22:10 -07:00
John Mizerek
24849c01e4 Fetch contact/about page during discovery for business info
- Detect contact/about/location/hours links on main page
- Fetch contact page and extract phone, address, hours
- Phone: regex for US phone formats + tel: links
- Address: US street address pattern (number + street type)
- Hours: day + time range patterns from plain text
- Overrides bad JSON-LD data with actual contact page info

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 18:26:19 -07:00
John Mizerek
b48f20011d Fix address parsing: proper US format detection (Street, City, ST ZIP)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 18:11:41 -07:00
John Mizerek
1df69463a8 Fix discovery business info extraction
- Prefer title tag for name over JSON-LD (sites often put address in LD name)
- Parse full address string into components (addressLine1, city, state, zip)
- Handle newlines in addresses (Squarespace puts newlines in JSON-LD)
- Convert 24h hours to 12h format
- Strip country suffix from addresses

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 18:09:54 -07:00
John Mizerek
a14213151f Extract per-menu schedule in extract_page mode
- Claude prompt now asks for menuSchedule (days/times this menu is served)
- Separates menu schedule from overall business hours
- Returns menuSchedule in response for frontend to use

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 17:45:05 -07:00
John Mizerek
571930ed25 Extract business info during discovery phase
- Parse JSON-LD structured data (Restaurant, FoodEstablishment, etc.)
- Extract phone from tel: links, address from og: meta tags
- Return businessInfo in discovery response so sub-pages don't need it

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 17:34:55 -07:00
John Mizerek
4ac13de09d Add discovery + multi-page extract modes for setup wizard
- Discovery mode: quick Playwright crawl returns detected menu sub-pages
- Extract_page mode: processes single menu page through Claude individually
- More aggressive HTML stripping: removes SVG, nav, footer, form, attributes
- Increased truncation limit from 100KB to 200KB for generic fallback path
- Enables interactive wizard flow: discover → confirm → extract each page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 17:03:54 -07:00
John Mizerek
552c404cf6 Server-side address parsing: split combined address into components
Claude returns address as one string with country suffix.
Now strips "United States/USA", extracts ZIP, state, splits
address line and city server-side before sending to wizard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 16:45:34 -07:00
John Mizerek
a7464545df Support multiple menus in wizard import (Brunch/Lunch/Dinner)
- Updated Claude prompt to detect separate menus vs categories
- Added platformImageMap and subPagesVisited parsing from Playwright
- Bumped Playwright wait from 5s to 10s for sub-page crawling
- saveWizard.php creates separate Menus rows and assigns categories/items
  to the correct menu based on each item's "menu" field

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 16:29:38 -07:00
John Mizerek
08ef54976f Port Twilio SMS integration from CFML to PHP
Add sendSMS() to helpers.php using Twilio REST API with cURL,
credentials loaded from config/twilio.json. Wire into sendOTP,
loginOTP, and sendLoginOTP endpoints, replacing TODO stubs.
SMS is auto-skipped on dev environments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 16:02:34 -07:00
John Mizerek
4d806d4e1e Port admin, cron, and receipt endpoints from CFML to PHP
- admin/quickTasks: list, create, save, delete
- admin/scheduledTasks: list, save, delete, toggle, run, runDue
- cron: expireStaleChats, expireTabs
- receipt: public order receipt page (no auth, UUID-secured)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 15:57:25 -07:00
John Mizerek
bd913bb46d Fix PUBLIC_ROUTES case-sensitivity bug in runAuth (strtolower path vs mixed-case routes) 2026-03-14 15:11:04 -07:00
John Mizerek
1f81d98c52 Initial PHP API migration from CFML
Complete port of all 163 API endpoints from Lucee/CFML to PHP 8.3.
Shared helpers in api/helpers.php (DB, auth, request/response, security).
PDO prepared statements throughout. Same JSON response shapes as CFML.
2026-03-14 14:26:59 -07:00