10 KiB
10 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
# Deploy: SCP to /tmp on dev, then sudo cp to biz.payfrit.com/ path
ssh dev.payfrit.com
# Canonical source of truth on dev:
# /opt/lucee/tomcat/webapps/ROOT/biz.payfrit.com/
# No local Lucee — all development happens on the dev server
Dev symlinks on dev server: /api, /portal, /config, /cron are all symlinks to biz.payfrit.com/. Always edit under biz.payfrit.com/ — never the root symlinks directly.
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-IDheader - Token Table:
UserTokens(Token, UserID) - Public Endpoints: ~50+ whitelisted in
api/Application.cfm(no token required) - OTP Flow: sendOTP → verifyOTP → token issued
- Magic OTP:
123456bypass 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:
payfritdatasource
Database
- Production:
payfriton db.payfrit.com (still uses OLD prefixed column names) - Development:
payfrit_devon db.payfrit.com (migrated to clean names)
Dev DB uses clean, unprefixed names. PKs are always ID. FKs reference their parent table (e.g., BusinessID, UserID). No table-name prefixes on columns.
Key tables (dev schema):
| 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 |
Order Status Flow
- 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_queryCountrequest._perf_queryTimeMs
Git Configuration
Ignored: config/claude.json, *.tmp, *.bak, api/admin/_scripts/
Common Tasks
Add new API endpoint
- Create
.cfmfile in appropriateapi/subdirectory - Public endpoints: add to allowlist in
api/Application.cfm - Authenticated endpoints work automatically via
X-User-Token
Add new portal page
- Create HTML file in
portal/ - Add routing/navigation in
portal.js
KDS customization
- Refresh interval:
config.refreshIntervalinkds.js - Station filtering via URL params