# FormBuilder Pro — Modular Edition
## Deployment & Upgrade Guide

---

## Fresh Install

1. Upload all files to your server (e.g. `public_html/formbuilder/`)
2. Set `data/` folder permissions to `755`
3. Run `setup.php` — creates DB tables, writes `config.php`, deletes itself
4. Log in to `admin.php`
5. **Set `APP_KEY`** in `config.php` (see below) — required for QR passes

---

## Upgrading from v1/v2

All schema changes run automatically on first request via `init_booking_db()`.
No manual SQL needed. The following are added safely with `IF NOT EXISTS`:

| Table / Column | Purpose |
|---|---|
| `sys_feature_toggles` | Module on/off switches |
| `bk_plans.session_limit` | Sessions included in plan (0 = unlimited) |
| `bk_memberships.sessions_remaining` | Current session count (NULL = unlimited) |
| `bk_checkins` | QR check-in log (append-only) |
| `bk_checkins.sessions_remaining` | Snapshot of sessions after each check-in |
| `bk_membership_log` | Audit trail for manual session adjustments |

---

## Required: Set APP_KEY

Open `config.php` and replace the placeholder:

```php
define('APP_KEY', 'change-this-to-a-32-char-random-secret-key');
```

Generate a strong key:
```bash
php -r "echo bin2hex(random_bytes(32));"
```

**Important:** Never change `APP_KEY` in production — it invalidates all existing
QR passes (customers will need to refresh their dashboard to get a new one).

---

## QR Code Library

The bundled `vendor/phpqrcode/qrlib.php` generates visually unique QR-like images
using PHP's GD extension. These are NOT standards-compliant QR codes and cannot
be scanned by a phone camera.

**For production check-in scanning, install one of:**

### Option A — phpqrcode (recommended for shared hosting)
```bash
# Download to vendor/phpqrcode/
wget https://raw.githubusercontent.com/t0k4rt/phpqrcode/master/qrlib.php \
  -O vendor/phpqrcode/qrlib.php
```

### Option B — endroid/qr-code (via Composer)
```bash
composer require endroid/qr-code
```
Then update `lib/QrPass.php` renderer 1 to use the installed version.

The `QrPass::png()` method tries renderers in this order:
1. `endroid/qr-code` (Composer)
2. `vendor/phpqrcode/qrlib.php` (file drop-in)
3. `api.qrserver.com` (external API — requires internet access from server)

---

## Module Toggles

After first login, go to **Admin → Modules** to enable/disable:

| Module | Key | Controls |
|---|---|---|
| Form Builder | `module_forms` | Forms, submissions, webhooks |
| Appointment Booking | `module_booking` | Services, providers, slot availability |
| Membership & Sessions | `module_membership` | Plans, session limits, QR check-in |

Toggling a module blocks its API (returns 403). Data is never deleted.
The Stripe webhook bypasses the booking toggle so memberships always activate.

---

## Session-Limited Plans (e.g. Swimming Course)

1. Go to **Admin → Booking → Plans & Services**
2. Create or edit a plan
3. Set **Session Limit** (e.g. `10` for 10 sessions over 90 days)
4. Link the plan to the relevant service (e.g. "Swimming Lesson")

When a customer buys this plan via Stripe:
- `sessions_remaining` is set to `10` on their membership
- Each booking deducts 1 session atomically inside a DB transaction
- At 0 sessions, booking is blocked with a "please renew" error
- On renewal (same plan re-purchased), sessions reset to `10`

Admin can manually adjust sessions: **Booking → Memberships → Adjust**

---

## QR Check-in Flow

1. Customer logs into their portal → sees their **Member Pass** QR code
2. Admin opens **Booking → Scan Pass**
3. Camera opens — point at customer's QR code
4. On success: customer name + sessions remaining shown as a toast
5. Check-in logged to `bk_checkins` with sessions snapshot

Manual fallback: expand "No camera?" in the scanner modal and paste the token.

Check-in history: **Booking → Check-in History** (filterable by date and method)

---

## Cron Job

Set up in cPanel:
```
*/30 * * * * curl -s "https://yourdomain.com/formbuilder/cron.php?key=YOUR_CRON_SECRET" > /dev/null
```

Sends 24h and 1h appointment reminder emails.

---

## File Structure (new files in this release)

```
lib/
  ModuleToggle.php      — isEnabled() / requireEnabled() / set()
  QrPass.php            — HMAC-signed QR token encode/decode/PNG
  BookingEngine.php     — + checkSessionLimit() + deductSession()
  StripeBooking.php     — + renewal logic + sessions_remaining on activation

api/
  admin/modules.php     — GET/POST module toggles
  booking/checkin.php   — QR check-in API (admin-auth required)
  booking.php           — + checkin route + adjust-sessions + checkins history
  index.php             — + module gates on all form/booking routes

admin/
  checkin.js            — CheckinScanner (camera + jsQR + manual fallback)
  booking.php           — + session progress bars + Adjust modal + Check-in History
  booking-plans.php     — + Session Limit field on plan modal

admin.php               — + Modules tab + module-aware dashboard stats + Scan Pass btn
customer/dashboard.php  — + session counter + QR pass card
config.php              — + APP_KEY + APP_DEBUG
lib.php                 — + all new tables auto-created in init_booking_db()

vendor/phpqrcode/
  qrlib.php             — GD stub (replace with real lib for production scanning)

migrations/
  002_module_toggles.php — standalone migration (also runs via init_booking_db)
```
