This repository has been archived on 2026-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
payfrit-biz/CLAUDE.md
John Mizerek 657bd33849 Document modifier template system, virtual IDs, and clean API key names in CLAUDE.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:51:32 -07:00

12 KiB

Payfrit Business Platform

Main CFML/JS repository: API + Portal + KDS + HUD + Receipt. Git repo on Forgejo; local clone at C:\dev\payfrit-biz.

Build & Deploy

# All edits in local clone
cd C:\dev\payfrit-biz

# Commit and push
git add <files>
git commit -m "message"
git push origin main

# Auto-deploy runs within ~1 minute to dev.payfrit.com

Git remote: git.payfrit.com (Forgejo) Dev server: dev.payfrit.com

HARD RULE: Always edit in C:\dev\payfrit-biz, never directly on the server or in C:\lucee\...

Project Structure

payfrit-biz/
├── Application.cfm              # Root app config: sessions (30min), datasource, layout wrapper
├── index.cfm                    # Legacy entry point, mode-based routing
├── onrequestend.cfm             # Footer/cleanup
├── register.cfm                 # Account registration
├── confirm_email.cfm            # Email verification
├── confirm_mobile.cfm           # Mobile verification
├── reset.cfm                    # Password reset
├── show_order.cfm               # Order detail (redirects to /receipt/)
├── privacy.html                 # Privacy policy
│
├── api/                         # REST API (~135 endpoints, 23 domains)
│   ├── Application.cfm          # Token auth gate (X-User-Token, X-Business-ID headers)
│   ├── config/
│   │   ├── stripe.cfm           # Stripe API keys
│   │   └── environment.cfm      # Dev vs prod settings
│   ├── addresses/               # CRUD delivery addresses (add, delete, list, setDefault, states, types)
│   ├── admin/                   # Admin utilities
│   │   ├── _scripts/            # One-off migration scripts (git-ignored)
│   │   ├── quickTasks/          # Task type/category management
│   │   └── scheduledTasks/      # Cron coordination
│   ├── app/                     # App info (about.cfm)
│   ├── assignments/             # Employee assignments (delete, list, save)
│   ├── auth/                    # Authentication (login, loginOTP, sendOTP, verifyOTP, profile, avatar)
│   ├── beacons/                 # Beacon management (CRUD, lookup, reassign)
│   ├── businesses/              # Business profiles (get, list, update, hours, hiring, brandColor)
│   ├── chat/                    # Order chat (send, get, markRead, close)
│   ├── debug/                   # Debug endpoints (localhost-protected)
│   ├── dev/                     # Dev tools (seedData, timeTravel)
│   ├── import/                  # Menu import (crimson_menu.cfm)
│   ├── menu/                    # Menu management (items, categories, menus, builder, photos)
│   ├── orders/                  # Order lifecycle (cart, submit, status, KDS list, history)
│   ├── portal/                  # Portal-specific (team, stats, settings, searchUser)
│   ├── ratings/                 # Customer ratings (create, list, submit)
│   ├── servicepoints/           # Service point CRUD
│   ├── setup/                   # Business onboarding wizard (analyze, import, save)
│   ├── stations/                # Kitchen stations (list)
│   ├── stripe/                  # Payments (createPaymentIntent, onboard, status, webhook)
│   ├── tasks/                   # Task system (accept, complete, create, list, types, categories)
│   ├── users/                   # User search
│   └── workers/                 # Worker system (account, onboarding, tier, ledger, earlyUnlock)
│
├── portal/                      # Business management SPA
│   ├── index.html               # Main dashboard
│   ├── login.html               # Portal login
│   ├── signup.html              # Business registration
│   ├── menu-builder.html        # Interactive menu builder
│   ├── setup-wizard.html        # Onboarding wizard
│   ├── station-assignment.html  # Station management
│   ├── quick-tasks.html         # Quick task interface
│   ├── portal.js                # Core JS (~169KB, vanilla JS, no framework)
│   └── portal.css               # Portal styles (~22KB)
│
├── kds/                         # Kitchen Display System
│   ├── index.html               # Full-screen kitchen display
│   ├── admin.html               # KDS admin
│   ├── debug.html               # Debug tools
│   └── kds.js                   # KDS logic (~17KB, 5-second polling)
│
├── hud/                         # Task HUD (Heads Up Display)
│   ├── index.html               # Full-screen task bars
│   └── hud.js                   # HUD logic (~12KB, 60s target times)
│
├── receipt/                     # Public receipt page (isolated app)
│   ├── Application.cfm          # Minimal config (no parent layout)
│   └── index.cfm                # Order receipt by UUID
│
├── admin/                       # Admin tools
│   ├── beacons.cfm              # Beacon management
│   ├── beacon_servicepoint.cfm  # Beacon-SP mapping
│   ├── email_users.cfm          # Bulk email
│   ├── god_mode.cfm             # Super-admin panel
│   └── servicepoints.cfm        # Service point management
│
├── library/cfc/                 # ColdFusion components
│   ├── businessMaster.cfc       # Business data abstraction
│   └── twilio.cfc               # SMS integration
│
├── includes/                    # Shared includes
│   ├── menu.cfm                 # Menu rendering
│   └── track_visitors.cfm       # Analytics
│
├── uploads/                     # User-generated content
│   ├── categories/              # Category images
│   ├── headers/                 # Business header images
│   ├── items/                   # Menu item photos
│   ├── logos/                   # Business logos
│   └── users/                   # User profile images
│
├── cron/
│   └── expireStaleChats.cfm     # Cleanup old chats
│
├── css/                         # Bootstrap 5.3.0 + custom
├── js/                          # jQuery 1.11/2.1, Bootstrap JS
├── fonts/                       # Glyphicons
├── images/                      # Logo assets
├── cfpayment/                   # Payment gateway library
└── twilio/                      # Twilio SMS

Key Files

File Purpose
api/Application.cfm Token auth, public endpoint allowlist, perf tracking, datasource config
Application.cfm Root session management (30min timeout), layout wrapper, business/twilio objects
portal/portal.js Main portal SPA logic (169KB, vanilla JS, Fetch API)
kds/kds.js Kitchen display polling & order status management
hud/hud.js Task visualization with time tracking & beacon alerts

API Authentication

  • Header: X-User-Token (64-char hex, SHA-256 based)
  • Business Context: X-Business-ID header
  • Token Table: UserTokens (Token, UserID)
  • Public Endpoints: ~50+ whitelisted in api/Application.cfm (no token required)
  • OTP Flow: sendOTP → verifyOTP → token issued
  • Magic OTP: 123456 bypass for App Store review

Environment Detection

Localhost (127.0.0.1):
  wwwrootprefix = /biz.payfrit.com/
  image_display_prefix = http://127.0.0.1:8888/biz.payfrit.com/uploads/
  uploads_dir = C:\lucee\tomcat\webapps\ROOT\biz.payfrit.com\uploads\

Production:
  wwwrootprefix = /
  image_display_prefix = https://biz.payfrit.com/uploads/
  uploads_dir = /var/www/biz.payfrit.com/uploads/

Tech Stack

  • Backend: CFML (Lucee), Application.cfm (not .cfc)
  • Portal/KDS/HUD: Vanilla JavaScript (no framework)
  • Root pages: jQuery 1.12.4 (CDN) + Bootstrap 5.3.0 (CDN)
  • Payments: Stripe (webhook at /api/stripe/webhook.cfm)
  • SMS: Twilio via twilio.cfc
  • Database: payfrit datasource

Database

Both payfrit (production) and payfrit_dev (development) use clean, unprefixed column names. PKs are always ID. FKs reference their parent table (e.g., BusinessID, UserID).

Key tables:

Table PK Key Columns
Businesses ID Name, UserID, Phone, BrandColor, TaxRate, OrderTypes, StripeAccountID, ParentBusinessID
Users ID FirstName, LastName, ContactNumber, EmailAddress, StripeCustomerId, UUID
Orders ID UUID, UserID, BusinessID, StatusID, OrderTypeID, ServicePointID, PaymentStatus
Items ID BusinessID, Name, Price, CategoryID, ParentItemID, IsActive, SortOrder, ImageExtension
Categories ID BusinessID, MenuID, ParentCategoryID, Name, OrderTypes, SortOrder
OrderLineItems ID ParentOrderLineItemID, OrderID, ItemID, StatusID, Price, Quantity, Remark
Tasks ID BusinessID, TaskTypeID, Title, Details, ClaimedByUserID, OrderID
ServicePoints ID BusinessID, Name, TypeID, Code, SortOrder, IsActive, BeaconID
Beacons ID BusinessID, UUID, Name, IsActive
Menus ID BusinessID, Name, IsActive
Employees ID BusinessID, UserID, StatusID, RoleID, IsActive
tt_StaffRoles ID Name (1=Staff, 2=Manager, 3=Admin)
lt_ItemID_TemplateItemID ItemID, TemplateItemID, SortOrder

Modifier Template System (IMPORTANT)

Modifier groups can be shared across multiple menu items via the template linking table lt_ItemID_TemplateItemID. A template is a top-level Item (ParentItemID=0, CategoryID=0) with child options. Menu items link to templates via the linking table, not via ParentItemID.

Example: "Cheeseburger Mods" (template) → children: "SIDE AVOCADO", "NO CHEESE", etc. Both CHEESEBURGER and DOUBLE CHEESEBURGER link to the same template.

Virtual IDs in items.cfm

items.cfm returns template-linked modifiers as virtual children of menu items with synthetic IDs:

  • Template group: virtualID = menuItemID * 100000 + templateItemID
  • Template option: virtualID = menuItemID * 100000 + optionItemID
  • ParentItemID is set to menuItemID (for template groups) or virtualTemplateID (for options)

This makes templates appear as regular children in the item tree. Mobile apps see them in itemsByParent[menuItemId] alongside any direct children.

Virtual ID Decoding in setLineItem.cfm

When receiving virtual IDs from clients: realItemID = virtualID MOD 100000 (if ItemID > 100000).

CRITICAL: API responses always return real ItemIDs, not virtual IDs. Clients must account for this round-trip: virtual IDs go out, real IDs come back.

API Response Key Names

All API endpoints use clean key names matching the database columns (e.g., ItemID, ParentOrderLineItemID, Price). Do NOT use old prefixed key names like OrderLineItemItemID — those are legacy and will cause key mismatches in client parsers.

Order Status Flow

  1. Cart (StatusID 1) → 2. Submitted (2) → 3. Preparing (3) → 4. Ready (4) → 5. Completed (5)

Receipt Page

  • URL: /receipt/index.cfm?UUID={orderUuid}
  • Separate Application.cfm — bypasses root layout
  • Public (no auth) — secured by v4 UUID unguessability
  • No internal data exposed (no platform fees, commissions, Stripe IDs)

Performance Tracking

API requests track:

  • request._perf_start (getTickCount)
  • request._perf_queryCount
  • request._perf_queryTimeMs

Git Configuration

Ignored: config/claude.json, *.tmp, *.bak, api/admin/_scripts/

Common Tasks

Add new API endpoint

  1. Create .cfm file in appropriate api/ subdirectory
  2. Public endpoints: add to allowlist in api/Application.cfm
  3. Authenticated endpoints work automatically via X-User-Token

Add new portal page

  1. Create HTML file in portal/
  2. Add routing/navigation in portal.js

KDS customization

  • Refresh interval: config.refreshInterval in kds.js
  • Station filtering via URL params