# Running Command

1. WhatSapp Meta Official Channel, its webhook funnel to local
ngrok http petav3.test:80 --host-header=rewrite

2. WhatSapp Qr Channel 
cd wa-bridge && npm start

3. For Windows (Ubuntu 22.04.5 LTS) 
cd /mnt/c/Users/zhish/work/petav3 (Change to your Path)
php artisan horizon
php artisan horizon:terminate
php artisan reverb:start
php artisan schedule:work

   Notes:
   - Run ALL THREE under WSL/Ubuntu (Horizon's daemon won't run on native Windows).
   - `php artisan schedule:work` is the SCHEDULER — without it NOTHING in
     app/Console/Kernel.php fires locally: no `whatsapp:ping-bridge` heartbeat (so
     `last_ping_at` never updates and dead bridge instances aren't revived from the
     Laravel side), no broadcast runner, no flow reaper, no avatar/quality sync.
     On prod this is the `petav3-scheduler` systemd unit (installed/restarted by
     `scripts/deploy-update.sh`); locally it must be started by hand.
     Check it from the browser anytime: Manage → System Health (Scheduler card +
     the "Upcoming schedule" table).
   - `php artisan horizon` does NOT hot-reload changed job/AI/flow code. After editing
     a job (e.g. GenerateAiReply / AdvanceFlowRun), run `php artisan horizon:terminate`
     so the workers restart with the new code (re-run `php artisan horizon` if it's foreground).
   - Without `reverb:start`, queued NewWhatsAppMessage / status broadcasts FAIL (harmless to
     the flow itself, but they pile into failed_jobs). Start Reverb for live inbox updates.


# Backfill: link existing WhatsApp contacts to their CRM lead / admin

   # ALWAYS dry-run first — a real run CREATES a CRM lead for (almost) every
   # unlinked contact the business has a 1:1 footprint with.
   php artisan whatsapp:link-contacts --dry-run            # report only, writes nothing
   php artisan whatsapp:link-contacts --dry-run --limit=200
   php artisan whatsapp:link-contacts                      # apply (creates leads + writes contact.user_id)

   Notes:
   - Links contact.user_id by matching the contact phone tolerantly to
     user_profiles.phone (a MY "+60123…" matches a stored "0123…"); a staff phone
     links to the admin user WITHOUT creating a lead; any other reachable phone
     gets a thin lead+user created (the chosen policy).
   - Skips sandbox test numbers (+1999…) AND group-only participants (contacts with
     no individual conversation) — a group bystander never becomes a CRM lead.
   - Safe to re-run (only touches user_id = NULL) — which is also the "reverse"
     sweep: a contact whose matching lead/profile appeared later links on the next run.
   - NEW contacts link automatically on their first genuine 1:1 inbound (no command
     needed) — this backfill is only for existing rows.


# Audit: flows whose template steps / proactive openers break the channel guards

   # Read-only — writes NOTHING. Run it once after deploying the channel-aware
   # template guards, so admins can fix legacy flows BEFORE their next save /
   # activate is blocked (that block is intended, not a regression).
   php artisan whatsapp:flows-audit                        # no arguments, no options

   Notes:
   - Walks every flow (any status) and warns on three things: a TEMPLATE step on a
     BRIDGE channel (the Bridge has no Meta templates), a template step that no
     longer matches an APPROVED non-Auth registry row for its channel (param counts
     included — the same `TemplateStepValidator` used at save / activate / send /
     sandbox), and an ACTIVE proactive CLOUD flow whose FIRST step is not a template
     (a fresh contact has no open 24h window, so a free-form opener dies silently).
   - Output is one warn line per issue — `[flow name] (channel · provider) step N: reason`
     — then a total; "All flows pass the channel-aware template guards." when clean.
   - Fix each flow on its edit page (pick an approved template / convert the step to
     text / give the proactive flow a template opener). See flow.md → *Channel-aware
     template rules*.


# QR (Bridge) channel — connection ops red lines

   - The paired PHONE must stay healthy: WhatsApp logs out ALL linked devices if the
     phone is unused for ~14 days. Keep it on charger + network, exclude WhatsApp from
     Android battery optimization, and open WhatsApp on it every few days.
   - NEVER re-register the number (new phone / reinstall / SIM re-verify) — that
     instantly 401s the bridge session; only a QR re-scan recovers it.
   - Do NOT enable a passkey on the bridge WhatsApp account — WhatsApp's WebAuthn
     pairing flow ("Shortcake", Baileys #2672) makes headless RE-PAIRING impossible.
   - Avoid unnecessary logout/re-pair cycles — rapid cycles trip a temporary
     server-side pairing throttle (Baileys #2691). Established sessions are the
     stable thing; protect them.
   - Never run TWO wa-bridge processes against the same DB/auth — the sockets 440
     conflict-replace each other (the bridge now parks a conflicted instance for
     5 min and logs it loudly).


# Testing the bot (AI Profile + Flow) WITHOUT a real WhatsApp number

   # one-time: seed a Sandbox channel + AI profile + keyword flow + Demo Customer
   php artisan db:seed --class='\WhatsappDemoSeeder'     # leading backslash REQUIRED

   # inject a customer message through the real pipeline, watch the thread + diagnose
   php artisan whatsapp:flow-test "hello, can I book a viewing?"
   php artisan whatsapp:flow-test "hi" --watch=60        # watch longer (Horizon latency)
   php artisan whatsapp:flow-test "hi" --sync            # run inline, no Horizon (single-step drip only)

   Run these under WSL too. The same thing is available in the UI: the Channels page
   "Sandbox" button + the violet "send as customer" bar in the inbox.


# Reference Data for WhatSapp Meta Official API (Local) 
Phone Number ID:
1124647047406443

WABA:
3631683546980934

Callback URL:  
https://japingly-isodiametric-omega.ngrok-free.dev/webhooks/whatsapp/cloud