226 lines
10 KiB
Markdown
226 lines
10 KiB
Markdown
# 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
|