- 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>
- 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>
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>
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>
- 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>
- 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>
- 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>
- 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>
- 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>
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>
- 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>
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>
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.