Commit graph

130 commits

Author SHA1 Message Date
John Mizerek
d6478da03f Fix brand color display and header upload collision
- Brand color: add # prefix when loading from DB (stored without #,
  CSS needs it for backgroundColor)
- Header upload: delete destination file before rename to prevent
  collision when re-uploading same extension
- Header preview: prepend BASE_PATH to image URL for local dev

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 09:10:45 -08:00
John Mizerek
db90d9911a Add OTP email login to business portal
Replace default password login with email-based OTP flow. User enters
email, receives 6-digit code, enters it to log in. Password login
retained as fallback via link. On dev, magic OTP code is shown directly
for easy testing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 09:03:40 -08:00
John Mizerek
3f15b0c8b6 Fix SQL injection, wrong PK, and hardcoded production URLs
Security:
- orders/submit.cfm: parameterize IN clause (was string-interpolated)
- auth/completeProfile.cfm: fix UserID → ID on Users table PK

Environment-aware URLs:
- Add application.baseUrl to config/environment.cfm
- Replace all hardcoded https://biz.payfrit.com with application.baseUrl in:
  orders/getDetail, tasks/getDetails, auth/completeProfile, auth/avatar,
  stripe/onboard, users/search, workers/onboardingLink, workers/earlyUnlock

Also fix submit.cfm qMeta.ItemID → qMeta.ID (column not in SELECT)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 21:14:19 -08:00
John Mizerek
e30a757c39 Fix missing datasource in addresses/list.cfm and LIKE on INT column in setDefault.cfm
- list.cfm: add missing datasource: "payfrit" parameter to queryExecute
- setDefault.cfm: change AddressTypeID LIKE '%2%' to AddressTypeID = 2 (INT column)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 21:05:06 -08:00
John Mizerek
3dc15f8c13 Fix TaskID → ID in WHERE clauses on Tasks table (4 files + cron copy)
- tasks/accept.cfm: WHERE TaskID → WHERE ID
- tasks/completeChat.cfm: WHERE TaskID → WHERE ID
- tasks/expireStaleChats.cfm: WHERE TaskID → WHERE ID
- cron/expireStaleChats.cfm: WHERE TaskID → WHERE ID
- chat/closeChat.cfm: WHERE TaskID → WHERE ID

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 21:00:46 -08:00
John Mizerek
a7b7717ccd Fix prefixed column names in uploadHeader, stripe/onboard, stripe/createPaymentIntent
- uploadHeader.cfm: WHERE BusinessID → WHERE ID (Businesses table PK)
- onboard.cfm: WHERE BusinessID → WHERE ID, BusinessStripeOnboardingStarted → StripeOnboardingStarted
- createPaymentIntent.cfm: WHERE BusinessID → WHERE ID, OrderDeliveryFee → DeliveryFee, WHERE OrderID → WHERE ID

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:56:35 -08:00
John Mizerek
09172ace40 Fix header image URL to use relative path instead of hardcoded production domain
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:52:19 -08:00
John Mizerek
89ec86c9d2 Move 70 one-off admin scripts to api/admin/_scripts/ (gitignored)
Only quickTasks/ and scheduledTasks/ subdirectories remain tracked
since those are actively used by the portal.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:38:49 -08:00
John Mizerek
78035e9cf6 Fix remaining prefixed DB column names across 17 API files
Hours: HoursBusinessID/HoursDayID/HoursOpenTime/HoursClosingTime -> BusinessID/DayID/OpenTime/ClosingTime
ServicePoints: ServicePointID/ServicePointName/ServicePointBusinessID -> ID/Name/BusinessID
Users: UserFirstName/UserLastName/UserEmailAddress/UserContactNumber -> FirstName/LastName/EmailAddress/ContactNumber
Orders: BusinessDeliveryMultiplier -> DeliveryMultiplier (column renamed in dev DB)
Businesses: BusinessParentBusinessID -> ParentBusinessID
tt_Days: tt_DayID/tt_DayName -> ID/Name

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:35:24 -08:00
John Mizerek
4f5ba7f549 Fix businesses/get.cfm: use un-prefixed dev DB column names
Hours query was still using HoursDayID, HoursOpenTime etc. which
don't exist in payfrit_dev. Now uses DayID, OpenTime, ClosingTime.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:06:52 -08:00
John Mizerek
8acf2f3249 Complete DB column normalization: strip redundant table-name prefixes from all SQL queries
Updated 70 files to match the payfrit_dev schema where columns like
BusinessName→Name, UserFirstName→FirstName, AddressCity→City, etc.
PKs renamed to ID, FKs keep referenced table name (e.g. BusinessID).
SQL aliases preserve original JSON response keys for API compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:03:40 -08:00
John Mizerek
c62895e464 Fix prefixed column names in admin, beacon, task, assignment, chat, rating APIs
Updated all remaining SQL queries to use correct prefixed column names for
ServicePoints, Users, Businesses, Addresses, tt_States, tt_Days, and Hours
tables across 23 admin/infrastructure API files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 17:55:16 -08:00
John Mizerek
39448c5d91 Fix prefixed column names in auth, orders, portal team, users search, workers APIs
Updated Users (UserID, UserFirstName, UserLastName, UserEmailAddress, UserContactNumber),
ServicePoints (ServicePointID, ServicePointName, ServicePointTypeID), and Businesses
(BusinessID, BusinessName, BusinessTaxRate, BusinessPhone) column references with proper
prefixed names and AS aliases for API compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 17:43:33 -08:00
John Mizerek
e92362f773 Fix prefixed column names for tt_States, tt_Days, tt_OrderTypes, ServicePoints, Users, Addresses, Hours tables
All lookup/reference tables use prefixed column names (tt_StateID, tt_StateAbbreviation,
tt_DayID, tt_DayAbbrev, tt_OrderTypeID, tt_OrderTypeName, ServicePointID, ServicePointName,
UserID, UserFirstName, UserLastName, AddressID, AddressLine1, etc). Updated all affected
queries to use correct column names with aliases to maintain API compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 17:38:33 -08:00
John Mizerek
6b66d2cef8 Fix normalized DB column names across all API files
Sweep of 26 API files to use prefixed column names matching the
database schema (e.g. BusinessID not ID, BusinessName not Name,
BusinessDeliveryFlatFee not DeliveryFlatFee, ServicePointName not Name).

Files fixed: auth, beacons, businesses, menu, orders, setup, stripe,
tasks, and workers endpoints.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 16:56:41 -08:00
John Mizerek
62c61c13cd Fix header upload: use normalized column names
- HeaderImageExtension -> BusinessHeaderImageExtension
- ID -> BusinessID in SELECT query

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 14:28:23 -08:00
John Mizerek
469cc06a29 Fix brand color save: use BusinessBrandColor column, allow # to be optional
- saveBrandColor.cfm: BrandColor -> BusinessBrandColor (normalized column name)
- portal.js: Accept hex colors with or without # prefix in validation
- portal.js: Auto-prepend # when typing bare hex in color input

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 14:27:44 -08:00
John Mizerek
498ebb6c0e Fix magic OTP on dev, fix portal login flash of login form
- loginOTP.cfm/sendOTP.cfm: Use magic OTP code (123456) on dev instead of random
- portal/login.html: Hide login card until auth check completes to prevent flash of login form when redirecting to business selection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 14:19:36 -08:00
John Mizerek
c5a332b04e Fix portal login: use normalized DB column names, fix business dropdown
- myBusinesses.cfm: Use BusinessID/BusinessName/BusinessUserID instead of
  ID/Name/UserID (post-normalization column names)
- login.html: Fix biz.BusinessName -> biz.Name to match API response key
- login.html: Add friendly error messages for bad_credentials
- portal.js: Fix b.ID -> b.BusinessID in access check

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 14:15:37 -08:00
John Mizerek
94ee89d1f3 Fix FK references on OrderLineItems incorrectly changed to ID
- setLineItem.cfm: WHERE ID→WHERE OrderID on 3 OrderLineItems queries
  that filter by order (FK), not by line item PK
- setLineItem.cfm: qKids.ItemID→qKids.ID, qTemplateKids.ItemID→
  qTemplateKids.ID (query only selects ID column from Items)
- abandonOrder.cfm: DELETE FROM OrderLineItems WHERE ID→WHERE OrderID
  (was deleting one line item by PK instead of all items for the order)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:30:10 -08:00
John Mizerek
8dff081407 Fix remaining old column names missed by initial batch rename
Second pass fixing 70+ references across 32 files:
- Orders: DeliveryMultiplier→BusinessDeliveryMultiplier, OrderTipAmount→TipAmount,
  OrderPaymentCompletedOn→PaymentCompletedOn, OrderPaymentError→PaymentError
- Orders PK: WHERE OrderID=? → WHERE ID=? on Orders table
- OrderLineItems PK: OrderLineItemID→ID in INSERT, WHERE, and query results
- Items: parent.ItemID→parent.ID in JOIN conditions
- Tasks: t.TaskID→t.ID in JOIN conditions
- Users PK: WHERE UserID=X → WHERE ID=X on Users table
- Addresses PK: A.AddressID→A.ID in JOIN conditions
- tt_States: tt_StateID→ID, remove nonexistent tt_StateCountryID/tt_StateSortOrder
- tt_OrderTypes: tt_OrderTypeID→ID, tt_OrderTypeName→Name
- tt_Days: D.tt_DayID→D.ID
- confirm_email.cfm: Add missing SELECT/FROM to queries
- setLineItem.cfm: Fix 13 old column references
- Stripe webhook/payment: Fix column names and PK references

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:58:46 -08:00
John Mizerek
712ec3b635 Show date and time on separate lines in perf dashboard card
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 18:22:40 -08:00
John Mizerek
d84805a6f4 Use h:nnt format, same font size, wider card for date
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 18:16:38 -08:00
John Mizerek
60de16437b Use m/d/yy h.nnp date format on perf dashboard
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 18:13:15 -08:00
John Mizerek
e92b2a4833 Fix perf dashboard date card to fit single line
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 18:09:58 -08:00
John Mizerek
cf1c6497ca Format date display in perf dashboard (Jan 29, 2026 8:46 PM)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 18:08:07 -08:00
John Mizerek
bc88f28e60 Fix UserID column references in auth endpoints after schema normalization
Users table primary key was renamed from UserID to ID but these
endpoints still referenced the old column name, causing server_error
on login/signup OTP flow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 17:15:46 -08:00
John Mizerek
bffca643b5 Restore API performance tracking and fix perf dashboard
- Add queryTimed(), logPerf(), flushPerfBuffer() to environment.cfm
- Auto-create ApiPerfLogs table on first flush
- Hook logPerf into Application.cfm apiAbort for automatic tracking
- Initialize request perf counters in Application.cfm
- Remove local apiAbort() overrides from 7 endpoints
- Instrument 12 high-traffic endpoints with logPerf calls
- Buffer metrics in application scope, batch INSERT every 100 requests
- 30-day auto-cleanup with probabilistic trigger

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 17:04:12 -08:00
John Mizerek
1210249f54 Normalize database column and table names across entire codebase
Update all SQL queries, query result references, and ColdFusion code to match
the renamed database schema. Tables use plural CamelCase, PKs are all `ID`,
column prefixes stripped (e.g. BusinessName→Name, UserFirstName→FirstName).

Key changes:
- Strip table-name prefixes from all column references (Businesses, Users,
  Addresses, Hours, Menus, Categories, Items, Stations, Orders,
  OrderLineItems, Tasks, TaskCategories, TaskRatings, QuickTaskTemplates,
  ScheduledTaskDefinitions, ChatMessages, Beacons, ServicePoints, Employees,
  VisitorTrackings, ApiPerfLogs, tt_States, tt_Days, tt_AddressTypes,
  tt_OrderTypes, tt_TaskTypes)
- Rename PK references from {TableName}ID to ID in all queries
- Rewrite 7 admin beacon files to use ServicePoints.BeaconID instead of
  dropped lt_Beacon_Businesses_ServicePoints link table
- Rewrite beacon assignment files (list, save, delete) for new schema
- Fix FK references incorrectly changed to ID (OrderLineItems.OrderID,
  Categories.MenuID, Tasks.CategoryID, ServicePoints.BeaconID)
- Update Addresses: AddressLat→Latitude, AddressLng→Longitude
- Update Users: UserPassword→Password, UserIsEmailVerified→IsEmailVerified,
  UserIsActive→IsActive, UserBalance→Balance, etc.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 15:39:12 -08:00
John Mizerek
dc9db32b58 Add API performance profiling, caching, and query optimizations
- Add queryTimed() wrapper and logPerf() for per-endpoint timing metrics
- Add api_perf_log table flush mechanism with background thread batching
- Add application-scope cache (appCacheGet/Put/Invalidate) with TTL
- Cache businesses/get (5m), addresses/states (24h), menu/items (2m)
- Fix N+1 queries in orders/history, orders/listForKDS (batch fetch)
- Fix correlated subquery in orders/getDetail (LEFT JOIN)
- Combine 4 queries into 1 in portal/stats (subselects)
- Optimize getForBuilder tree building with pre-indexed parent lookup
- Add cache invalidation in update, saveBrandColor, updateHours, saveFromBuilder
- New admin/perf.cfm dashboard (localhost-protected)
- Instrument top 10 endpoints with queryTimed + logPerf

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 20:41:27 -08:00
John Mizerek
a5fa1c1041 Skip empty categories in menu API response
Only include category headers that actually have items assigned
to them, preventing empty categories from showing up in the app.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 22:29:38 -08:00
John Mizerek
6b31b1abcf Remove time-based filtering from customer menu API
Always return all active menus in the response so chip selector
always appears. Show all items from all menus by default instead
of filtering by current time, which caused empty results outside
menu hours.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 22:18:10 -08:00
John Mizerek
3b48c3331d Add menu list and MenuID filter to items.cfm API
Returns active menus in response so mobile apps can show menu
selector chips. Accepts optional MenuID param to filter items
to a specific menu.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 20:54:37 -08:00
John Mizerek
9091461079 Auto-select active menu based on current time, allow manual override
When multiple menus exist, checks current time and day against menu
schedules. If exactly one menu matches, auto-selects it. If times
overlap or none match, shows all categories. User can still manually
select any menu or 'All Menus' from the dropdown.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 18:13:44 -08:00
John Mizerek
41ef1631ef Allow menu deletion when categories exist - unassign instead of block
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 18:01:51 -08:00
John Mizerek
3613776ff3 Fix undefined menuName in saveWizard when using provided menuId
The menuName variable was only defined in the else branch (new menu
creation) but referenced later in category logging. Now looks up the
menu name from DB when using a provided menuId.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 17:54:16 -08:00
John Mizerek
ec6bfdd9c9 Fix menu save: javaCast null breaks variable access in Lucee 7
javaCast('null','') makes the variable truly undefined, causing
'variable doesn't exist' errors when referenced in query params.
Use empty string + len() check instead.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 17:33:21 -08:00
John Mizerek
02a19f52be Add menu wizard flow: redirect to setup wizard after creating a new menu
When a new menu is created in Manage Menus, the user is now redirected
to the setup wizard with businessId and menuId params. The wizard skips
business info/header steps and goes straight to photo upload + category
extraction. Backend uses the provided menuId instead of creating a new
menu. Also removes temp debug from menus.cfm.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 17:08:31 -08:00
John Mizerek
65cf855ade Add menu/menus.cfm to public paths so menu save works
The endpoint was missing from the public paths whitelist in
Application.cfm, causing all requests to fail with not_logged_in.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 16:57:51 -08:00
John Mizerek
df64f161f3 Add debug tagcontext to menu save error response (temporary)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 16:56:00 -08:00
John Mizerek
6b4e5cc369 Add cfsqltype hints for nullable time params in menu save
Fixes save failure when MenuStartTime/MenuEndTime are null -
Lucee couldn't determine the SQL type without explicit hints.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 16:53:34 -08:00
John Mizerek
c6a45f7024 Fix CFML hash escaping in brand color migration script
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 15:17:46 -08:00
John Mizerek
7bba0fb511 Add one-time script to strip # from existing brand colors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 15:11:01 -08:00
John Mizerek
cc96d891b2 Store brand color without # prefix, normalize on output
saveBrandColor.cfm no longer prepends # before storing. API responses
(get.cfm, items.cfm, getForBuilder.cfm) prepend # if missing so
consumers always get a CSS-ready value.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 14:58:58 -08:00
John Mizerek
8f9da2fbf0 Add Manage Menus toolbar button, photo upload, and various improvements
- Move menu manager button to toolbar next to Save Menu for visibility
- Implement server-side photo upload for menu items
- Strip base64 data URLs from save payload to reduce size
- Add scheduled tasks, quick tasks, ratings, and task categories APIs
- Add vertical support and brand color features

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 14:43:41 -08:00
John Mizerek
0d3c381ed6 Add about.cfm API endpoint for mobile app About screennAdds server-side content for About Payfrit screen allowing content updates without releasing new app versions.nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> 2026-01-28 00:38:58 -08:00
John Mizerek
400df7624f Simplify address API - delivery addresses only
- Remove TypeID/Label from list response
- Hardcode TypeID=2 (delivery) in add endpoint
- Filter to personal addresses only (BusinessID=0 or NULL)
- Just IsDefault flag, no home/work labels

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 00:12:18 -08:00
John Mizerek
6d5620d513 Filter out business addresses from user address list 2026-01-28 00:02:25 -08:00
John Mizerek
cadc66e46a Add address types endpoint, fix dev mode SMS skip
- Add /addresses/types.cfm - returns address types list
- Update /addresses/list.cfm - include TypeID in response
- Update /addresses/add.cfm - accept TypeID instead of hardcoded '2'
- Fix loginOTP.cfm and sendOTP.cfm to skip Twilio SMS on dev server

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 00:00:01 -08:00
John Mizerek
d4cc4b4a6c Fix service bell task creation for Android app
- Update create.cfm to handle TaskTypeID for service bell tasks
- Update hud.js to prefer TaskTypeColor/TaskTypeName for task display

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 20:52:59 -08:00