# 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

```bash
# 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

- **Production**: `payfrit` on db.payfrit.com (still uses OLD prefixed column names)
- **Development**: `payfrit_dev` on 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

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
