Business Logic & Workflows
Core business processes, background jobs, scheduled tasks, and data flow patterns.
Core Workflows
1. Member Onboarding
User invited to organisation
Admin creates user record with organisation and location assignment
License created
Binds user + organisation + membership tier + space. Triggers license job.
Line item generated
License job creates recurring line item with pricing from membership (primary vs extra member rates)
Welcome email sent
User job sends welcome mail with JWT token, WiFi credentials, and onboarding instructions
Access provisioned
RADIUS WiFi user auto-created. Papercut print account synced. Clay access group assigned.
2. Monthly Invoice Run
Admin initiates invoice run
Reviews preview for a location showing all active organisations and calculated amounts
Line items calculated
Sum from active licenses + adhoc charges. Apply discounts (commitment, volume). Pro-rata for mid-month changes.
Invoice approved
Status becomes "subscription_locked". Xero invoice created with line items, tracking codes, and tax.
Invoice sent
Emailed to organisation contacts (invoice + accounting email addresses). Status unlocked after send.
Payment processed
If auto-pay enabled, PayFast charges stored token. Otherwise manual payment via portal.
Fulfillment
Line items processed by type: stuff/space credits → wallet topup, printing → Papercut balance adjustment
3. Room Booking
Member selects room and time
System checks availability, applies access control (private rooms), calculates cost
Cost calculated
Peak (8am-5pm) vs off-peak rates. Half-day (4+ hrs) and full-day (8+ hrs) discounts applied.
Ledger reserve created
Funds held in wallet via reserve transaction. Reserve expires after 24 hours (configurable).
Notifications sent
iCal attachment to organiser and attendees. Location manager gets admin notification.
Reserve converted or expired
Cron job converts expired reserves to debits every 60 seconds. Cancelled bookings delete reserves.
4. Sales Pipeline (CRM)
Lead created
From web form (with reCAPTCHA), manual entry, or external integration. Heat rated (hot/mild/cold).
Opportunity opened
Track template auto-generates task tree with cascading due dates
Tasks worked
Follow-up calls, emails, meetings, site visits tracked. Email history from Mailarchiva.
Won or abandoned
Won: triggers onboarding. Referral rewards credited to wallet if referral source. Abandoned: reason captured, lead archived.
5. Self-Service Purchase
Member browses products
Filtered by location + headquarters. Shows member discounts.
Payment
Via stored PayFast token (one-click) or wallet credit deduction. VAT calculated.
Fulfillment
Product type determines action: stuff → wallet topup, space → wallet topup, printing → Papercut balance.
6. Check-in / Presence
Guest: QR code scan
Enter email/name, accept terms. Guest record created or updated. Confirmation emails sent.
Member: Direct login
Session-based authentication. Check-in record created with timestamp.
Federated: Unikey PIN
Encrypted PIN validated against external WSM instances. WiFi provisioned on check-in.
Background Job Processing
Jobs are triggered via Google Cloud Pub/Sub messages and processed by packages/jobs/worker.js.
| Job Type | Trigger | Actions |
|---|---|---|
| Booking | POST/PUT/DELETE on booking | Send iCal invite, update notification, or cancellation to organiser + attendees + location manager |
| User | User creation/update | Onboarding: create license, send welcome email with JWT + WiFi creds, setup Papercut/RADIUS |
| License | License CRUD | Create/update/delete line items. Generate pricing with Xero codes. Update user memberships. |
| Invoice | Invoice status change | Purchase fulfillment by product type (stuff/space/printing wallet topups). Lineitem normalisation. VAT handling. |
| Payment | Payment trigger | One-click PayFast charge. Xero payment recording. Organisation-wide payment processing. |
| Membership | Membership CRUD | Xero sync: create item codes with location-specific tracking names |
| Discount | Discount changes | Set escalation dates based on commitment discount expiry |
| Various triggers | Template-based HTML email rendering and sending via Nodemailer | |
| Lead | Lead lifecycle events | CRM notifications, status updates |
| Organisation | Org changes | Xero contact sync, membership updates, access control changes |
| Product | Product CRUD | Xero item sync with location tracking codes |
Scheduled Tasks (Cron)
The cron scheduler (packages/cron/cron.js) runs every minute, checking for "due" schedule records. It prevents concurrent execution with a locking mechanism.
| Task | Frequency | Purpose |
|---|---|---|
| Xero Token Refresh | Every minute | Refreshes OAuth token to prevent API auth failures. Sends alert email on failure. |
| Xero Cache Update | Every hour | Pre-fetches credit notes and payments for faster dashboard loading |
| Ledger Reserve Cleanup | Every 60 seconds | Converts expired booking reserves to actual debits |
| Wallet Quota Top-ups | Daily/Weekly/Monthly/Annually | Resets credit quotas per configured frequency |
| Health Check | Every minute (commented out) | Monitors stuck jobs, alerts if stuck > 1 hour |
Key Business Rules
Pricing Model
- Primary member: Pays base membership cost
- Extra members: Pay
cost_extra_membersurcharge - Pro-rata: Mid-month license changes calculate proportional costs
- Escalation: Annual price increases on scheduled dates with configurable percentage
- Commitment discounts: Time-limited discounts that expire on a set date
- Invoice holidays: Organisations can pause invoicing for defined periods
Booking Cost Calculation
- Peak slots (8am-5pm): Base room rate
- Off-peak slots (7-8am, 5-9pm): Reduced
off_peak_cost - Half-day (4+ hours): Percentage discount + room-level
half_day_discount - Full-day (8+ hours): Higher percentage discount + room-level
full_day_discount - Slot size: 30-minute intervals from 7am to 9pm
- Grace period: 5 minutes (configurable) before reservation expires
Wallet Deduction Logic
- Multiple wallets per user, each with a priority value
- Debits deduct from highest-priority wallet first
- Overflow: If a wallet has overflow enabled and insufficient balance, excess goes to the
overflow_towallet - Parking wallets: Auto-created if needed, debits always use dedicated parking wallet
- Reserve pattern: Bookings create reserves (negative amounts with expiry), converted to debits on expiry
- Only admins can credit wallets (non-admins only on transfers)
Invoice Lifecycle
- Status flow: Draft → Authorised → Paid
- Subscription invoices lock during approval/send workflow
- Self-service invoices only fulfill when status is PAID
- Credit notes supported for adjustments
- Line items snapshot as SentLineItems at send time
Lead Spam Prevention
- Google reCAPTCHA validation on web form submissions
- Automatic spam flagging for
.ruemail domains - Website lead source requires URL field
- Spam filter applied only to newly created leads
Critical Data Flow Patterns
Financial Flow
Sales Pipeline Flow
Access Control Flow
Workflow Summary
| Process | Trigger | Key Steps | Duration |
|---|---|---|---|
| Member Onboarding | New user | Welcome mail → License → Line item → Access provisioning | Immediate |
| Monthly Invoicing | Admin action | Calculate → Approve → Send → Pay → Fulfill | Manual + Scheduled |
| Room Booking | Member action | Create → Reserve funds → Notify → Convert/expire | Per booking |
| Self-Service Purchase | Member action | Browse → Pay → Fulfill (wallet topup) | Immediate |
| Check-in | Guest/Member | Scan/Login → Record → Email notification | Real-time |
| CRM Opportunity | Sales team | Lead → Opportunity → Tasks → Win/Lose → Archive | Days to months |
| License Lifecycle | Admin action | Create → Line item → Invoice → Pay → Fulfill | Monthly |
| Price Escalation | Scheduled | Check dates → Apply percentage → Update line items | Annual |