mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
Merge pull request #59 from ArnasDon/docs/full-setup-guide
docs: end-to-end self-host setup guide
This commit is contained in:
commit
f18adf3b47
51
README.md
51
README.md
@ -1,36 +1,43 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
# WaCRM
|
||||
|
||||
## Getting Started
|
||||
Self-hostable WhatsApp CRM — shared inbox, contacts, sales pipelines,
|
||||
broadcasts, and no-code automations — built on Next.js 16 and Supabase.
|
||||
|
||||
First, run the development server:
|
||||
- **Live demo / marketing site**: [`/`](./src/app/page.tsx)
|
||||
- **Source**: <https://github.com/ArnasDon/wacrm>
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your-username>/wacrm.git
|
||||
cd wacrm
|
||||
npm install
|
||||
cp .env.local.example .env.local
|
||||
# Fill in Supabase keys + ENCRYPTION_KEY, then:
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
Open <http://localhost:3000>.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
For the full setup — Supabase migrations, WhatsApp Business API config,
|
||||
production deploy on Hostinger — see [`docs/`](./docs/README.md).
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
## Documentation
|
||||
|
||||
## Learn More
|
||||
- [Getting started](./docs/getting-started.md)
|
||||
- [Supabase setup](./docs/supabase-setup.md)
|
||||
- [WhatsApp setup](./docs/whatsapp-setup.md)
|
||||
- [Environment variables](./docs/environment-variables.md)
|
||||
- [Deploy on Hostinger](./docs/deployment-hostinger.md)
|
||||
- [Automations cron](./docs/automations-and-cron.md)
|
||||
- [Troubleshooting](./docs/troubleshooting.md)
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
## Stack
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
- **App** — Next.js 16 (App Router), React 19, TypeScript, Tailwind v4.
|
||||
- **Data** — Supabase (Postgres + Auth + RLS).
|
||||
- **WhatsApp** — Meta Cloud API (official WhatsApp Business API).
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
## License
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
MIT — fork it, brand it, host it. Pull requests welcome.
|
||||
|
||||
43
docs/README.md
Normal file
43
docs/README.md
Normal file
@ -0,0 +1,43 @@
|
||||
# WaCRM documentation
|
||||
|
||||
WaCRM is a self-hostable WhatsApp CRM built on Next.js and Supabase. These
|
||||
docs walk you from a freshly forked repo to a production deploy.
|
||||
|
||||
## Reading order
|
||||
|
||||
1. **[Getting started](./getting-started.md)** — fork the repo, install, run
|
||||
locally.
|
||||
2. **[Supabase setup](./supabase-setup.md)** — create the database, run the
|
||||
migrations, grab the keys.
|
||||
3. **[WhatsApp setup](./whatsapp-setup.md)** — create a Meta app, connect a
|
||||
phone number, wire the webhook.
|
||||
4. **[Environment variables](./environment-variables.md)** — the full reference.
|
||||
5. **[Deploy on Hostinger](./deployment-hostinger.md)** — recommended hosting
|
||||
walkthrough (Node.js VPS).
|
||||
6. **[Automations cron](./automations-and-cron.md)** — schedule the pending
|
||||
executions drain so waits and delays fire.
|
||||
7. **[Troubleshooting](./troubleshooting.md)** — the usual suspects.
|
||||
|
||||
## What you will need before starting
|
||||
|
||||
- A GitHub account (to fork the repo).
|
||||
- A [Supabase](https://supabase.com) project on any paid or free tier.
|
||||
- A [Meta for Developers](https://developers.facebook.com) account with a
|
||||
WhatsApp Business app.
|
||||
- A WhatsApp phone number that is **not** already tied to the regular
|
||||
WhatsApp or WhatsApp Business mobile apps.
|
||||
- A [Hostinger](https://www.hostinger.com/vps-hosting) VPS plan (or any Node
|
||||
host that supports long-running Node.js 20+ processes).
|
||||
|
||||
## Stack at a glance
|
||||
|
||||
- **Frontend / API** — Next.js 16 (App Router), React 19, Tailwind v4.
|
||||
- **Database + auth + storage** — Supabase (Postgres + RLS).
|
||||
- **WhatsApp transport** — Meta Cloud API (official WhatsApp Business API).
|
||||
- **Encryption** — AES-256-CBC for per-user access tokens.
|
||||
- **Scheduler** — external cron that pings `GET /api/automations/cron`.
|
||||
|
||||
## Getting help
|
||||
|
||||
If something is unclear or broken, open an issue against the source repo:
|
||||
<https://github.com/ArnasDon/wacrm/issues>.
|
||||
85
docs/automations-and-cron.md
Normal file
85
docs/automations-and-cron.md
Normal file
@ -0,0 +1,85 @@
|
||||
# Automations cron
|
||||
|
||||
WaCRM's **Automations** module lets you build flows that react to WhatsApp
|
||||
events (new message, new contact, keyword match, schedule, etc.). Most
|
||||
steps run inline — the exception is the **Wait** step, which parks the
|
||||
execution in `automation_pending_executions` until its due time.
|
||||
|
||||
A cron job has to drain that table. If you skip this, Wait steps never
|
||||
resume and any flow that uses them stalls.
|
||||
|
||||
## The endpoint
|
||||
|
||||
```
|
||||
GET /api/automations/cron
|
||||
Header: x-cron-secret: <AUTOMATION_CRON_SECRET>
|
||||
```
|
||||
|
||||
- Returns `{ "processed": <n> }` with how many rows were claimed.
|
||||
- Returns `503` if the env var is not set.
|
||||
- Returns `401` if the header is missing or wrong.
|
||||
|
||||
The route claims up to 50 pending rows per call via a two-step
|
||||
UPDATE-by-id so overlapping calls don't double-process.
|
||||
|
||||
## 1. Generate the secret
|
||||
|
||||
Any long random string works. One option:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
Copy the result into `AUTOMATION_CRON_SECRET` in your deployment env.
|
||||
|
||||
## 2. Schedule the pinger
|
||||
|
||||
### Option A — cron on the same VPS (Hostinger)
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
```
|
||||
|
||||
```cron
|
||||
* * * * * curl -s -H "x-cron-secret: $AUTOMATION_CRON_SECRET" https://crm.example.com/api/automations/cron > /dev/null
|
||||
```
|
||||
|
||||
Export the secret into the cron environment. The simplest way is to add
|
||||
it to the user's shell profile and wrap the command:
|
||||
|
||||
```cron
|
||||
* * * * * bash -lc 'curl -s -H "x-cron-secret: $AUTOMATION_CRON_SECRET" https://crm.example.com/api/automations/cron > /dev/null'
|
||||
```
|
||||
|
||||
Or, for a more disciplined setup, use a `systemd` timer with
|
||||
`EnvironmentFile=/etc/wacrm.env`.
|
||||
|
||||
### Option B — external pinger
|
||||
|
||||
Any uptime monitor that supports custom headers works:
|
||||
|
||||
- [UptimeRobot](https://uptimerobot.com) — "Keyword Monitoring" with
|
||||
custom HTTP headers.
|
||||
- [Better Stack](https://betterstack.com).
|
||||
- GitHub Actions with a `schedule:` trigger.
|
||||
|
||||
Hit the URL once per minute. Anything slower just means Wait-step
|
||||
resolution is that much more delayed.
|
||||
|
||||
## 3. Verify
|
||||
|
||||
```bash
|
||||
curl -s -H "x-cron-secret: <secret>" https://crm.example.com/api/automations/cron
|
||||
# -> {"processed":0}
|
||||
```
|
||||
|
||||
Then create a test automation with a short Wait step (e.g., 30 seconds)
|
||||
and trigger it. Watch the automation's **Logs** tab — the execution
|
||||
should resume and mark as completed within one cron interval of the wait
|
||||
expiring.
|
||||
|
||||
## 4. What if you don't use Wait?
|
||||
|
||||
Skip this page. Trigger → inline steps → done flows do not need a cron —
|
||||
they finish synchronously inside the webhook handler or from the UI. The
|
||||
cron only matters for flows that park execution.
|
||||
161
docs/deployment-hostinger.md
Normal file
161
docs/deployment-hostinger.md
Normal file
@ -0,0 +1,161 @@
|
||||
# Deploy on Hostinger
|
||||
|
||||
Hostinger's **VPS Hosting** plans are the recommended way to run WaCRM in
|
||||
production: you get a dedicated Node.js process, predictable pricing, and
|
||||
Hostinger's `hPanel` handles SSL and firewalls for you.
|
||||
|
||||
This walkthrough uses a VPS running Ubuntu 24.04.
|
||||
|
||||
## 1. Provision the VPS
|
||||
|
||||
1. Sign up at <https://www.hostinger.com/vps-hosting> and pick a plan. The
|
||||
**KVM 2** tier (2 vCPU / 8 GB RAM) is a comfortable starting point.
|
||||
2. During the setup wizard:
|
||||
- **OS template** → Ubuntu 24.04 (plain, not the managed Node template —
|
||||
we install what we need manually).
|
||||
- **Location** → region closest to your users.
|
||||
- **SSH key** → upload your public key (`~/.ssh/id_ed25519.pub` or
|
||||
similar) so you can SSH in passwordless.
|
||||
3. Wait for provisioning. In hPanel you will see the IPv4 address and
|
||||
root credentials.
|
||||
|
||||
## 2. SSH in and install dependencies
|
||||
|
||||
```bash
|
||||
ssh root@<your-ip>
|
||||
|
||||
# Create a non-root user for the app
|
||||
adduser wacrm
|
||||
usermod -aG sudo wacrm
|
||||
rsync --archive --chown=wacrm:wacrm ~/.ssh /home/wacrm
|
||||
|
||||
# Switch user
|
||||
su - wacrm
|
||||
|
||||
# Install Node.js 20 LTS
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs git
|
||||
|
||||
# Install PM2 for process management
|
||||
sudo npm install --global pm2
|
||||
```
|
||||
|
||||
## 3. Clone your fork
|
||||
|
||||
```bash
|
||||
cd ~
|
||||
git clone https://github.com/<your-username>/wacrm.git
|
||||
cd wacrm
|
||||
npm ci
|
||||
```
|
||||
|
||||
## 4. Configure env vars
|
||||
|
||||
Create `/home/wacrm/wacrm/.env.local` with the values from
|
||||
[environment-variables.md](./environment-variables.md). Make sure
|
||||
`NEXT_PUBLIC_SITE_URL` is set to the exact public URL you will use
|
||||
(e.g., `https://crm.example.com`).
|
||||
|
||||
```bash
|
||||
chmod 600 .env.local
|
||||
```
|
||||
|
||||
## 5. Build and start with PM2
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pm2 start npm --name wacrm -- start
|
||||
pm2 save
|
||||
pm2 startup systemd -u wacrm --hp /home/wacrm
|
||||
# Follow the command PM2 prints — it enables auto-start on reboot.
|
||||
```
|
||||
|
||||
WaCRM is now listening on `127.0.0.1:3000`.
|
||||
|
||||
## 6. Front with nginx + SSL
|
||||
|
||||
Point your domain's `A` record at the VPS IP. Then:
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y nginx certbot python3-certbot-nginx
|
||||
```
|
||||
|
||||
Create `/etc/nginx/sites-available/wacrm`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name crm.example.com;
|
||||
|
||||
client_max_body_size 25m; # WhatsApp media upload ceiling
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
listen 80;
|
||||
}
|
||||
```
|
||||
|
||||
Enable and issue a cert:
|
||||
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/wacrm /etc/nginx/sites-enabled/wacrm
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
sudo certbot --nginx -d crm.example.com
|
||||
```
|
||||
|
||||
Certbot writes the 443 block, enables HTTP→HTTPS redirect, and schedules
|
||||
renewals in `systemd`.
|
||||
|
||||
## 7. Firewall
|
||||
|
||||
hPanel → **Firewall**: allow inbound 22 (SSH), 80, 443. Everything else
|
||||
stays closed.
|
||||
|
||||
## 8. Update the Meta webhook
|
||||
|
||||
Back in **Meta for Developers → WhatsApp → Configuration**, change the
|
||||
callback URL to `https://crm.example.com/api/whatsapp/webhook` and re-verify.
|
||||
|
||||
## 9. Schedule the automation cron
|
||||
|
||||
Follow [automations-and-cron.md](./automations-and-cron.md) to drain
|
||||
pending executions. A simple `cron` entry on the same VPS works:
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
```
|
||||
|
||||
```cron
|
||||
* * * * * curl -s -H "x-cron-secret: $AUTOMATION_CRON_SECRET" https://crm.example.com/api/automations/cron > /dev/null
|
||||
```
|
||||
|
||||
Load `AUTOMATION_CRON_SECRET` into the cron environment via
|
||||
`/etc/environment` or an `EnvironmentFile=` in a `systemd` unit.
|
||||
|
||||
## 10. Deploying updates
|
||||
|
||||
```bash
|
||||
ssh wacrm@<your-ip>
|
||||
cd ~/wacrm
|
||||
git pull
|
||||
npm ci
|
||||
npm run build
|
||||
pm2 reload wacrm
|
||||
```
|
||||
|
||||
`pm2 reload` performs a zero-downtime restart. If the database schema
|
||||
changed, apply any new SQL files from `supabase/migrations/` in the
|
||||
Supabase SQL editor first — migrations are idempotent.
|
||||
|
||||
## Where to go next
|
||||
|
||||
- [Automations cron →](./automations-and-cron.md) — must-do if you use
|
||||
the Wait step in any automation.
|
||||
- [Troubleshooting →](./troubleshooting.md) — common deploy issues.
|
||||
60
docs/environment-variables.md
Normal file
60
docs/environment-variables.md
Normal file
@ -0,0 +1,60 @@
|
||||
# Environment variables
|
||||
|
||||
All runtime configuration lives in `.env.local` during development and in
|
||||
your host's environment settings in production. `.env.local.example` is a
|
||||
minimal template; the table below is the full reference.
|
||||
|
||||
## Required
|
||||
|
||||
| Variable | Where to find it | Notes |
|
||||
| --------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| `NEXT_PUBLIC_SUPABASE_URL` | Supabase → Project Settings → API → **Project URL** | Public. Shipped to the browser. |
|
||||
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase → Project Settings → API → **anon / public** key | Public. Relies on RLS for safety. |
|
||||
| `SUPABASE_SERVICE_ROLE_KEY` | Supabase → Project Settings → API → **service_role** key | **Secret.** Bypasses RLS. Used by webhook + admin routes only. |
|
||||
| `ENCRYPTION_KEY` | Generate: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` | 64 hex chars (32 bytes, AES-256-CBC). **Rotating breaks existing tokens.** |
|
||||
|
||||
## Recommended
|
||||
|
||||
| Variable | Purpose |
|
||||
| ---------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `META_APP_SECRET` | Meta → App Settings → Basic → **App Secret**. Enables `X-Hub-Signature-256` verification on incoming webhooks. |
|
||||
| `NEXT_PUBLIC_SITE_URL` | Canonical public URL (e.g., `https://crm.example.com`). Used for absolute URLs, sitemap, OG images. |
|
||||
|
||||
## Optional
|
||||
|
||||
| Variable | Purpose |
|
||||
| --------------------------- | -------------------------------------------------------------------------------------------------------- |
|
||||
| `AUTOMATION_CRON_SECRET` | Shared secret that protects `GET /api/automations/cron`. Required if you schedule the automations drain. See [automations-and-cron.md](./automations-and-cron.md). |
|
||||
|
||||
## Sample `.env.local`
|
||||
|
||||
```bash
|
||||
# Supabase
|
||||
NEXT_PUBLIC_SUPABASE_URL=https://abcd1234.supabase.co
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOi...
|
||||
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOi...
|
||||
|
||||
# Encryption — DO NOT change after first deploy
|
||||
ENCRYPTION_KEY=3f9c0a7e4d8b2f1a6c5e8d4b9f0a2c6e8d4b9f0a2c6e8d4b9f0a2c6e8d4b9f0a
|
||||
|
||||
# Public URL + Meta webhook signing
|
||||
NEXT_PUBLIC_SITE_URL=https://crm.example.com
|
||||
META_APP_SECRET=abcdef0123456789...
|
||||
|
||||
# Automation cron
|
||||
AUTOMATION_CRON_SECRET=generate-a-long-random-string
|
||||
```
|
||||
|
||||
## Security checklist
|
||||
|
||||
- Never commit `.env.local`. The repo already ignores it.
|
||||
- On Hostinger / any VPS, set env vars via the platform's **Environment**
|
||||
panel rather than writing them into a tracked file on disk.
|
||||
- Rotate `SUPABASE_SERVICE_ROLE_KEY` if it leaks — Supabase lets you
|
||||
regenerate it under Project Settings → API.
|
||||
- Treat `ENCRYPTION_KEY` like a database master key. Losing it means
|
||||
connected WhatsApp accounts must reconnect; rotating it means the same.
|
||||
|
||||
## Next step
|
||||
|
||||
[Deploy on Hostinger →](./deployment-hostinger.md)
|
||||
79
docs/getting-started.md
Normal file
79
docs/getting-started.md
Normal file
@ -0,0 +1,79 @@
|
||||
# Getting started
|
||||
|
||||
Run WaCRM locally in about 15 minutes. This guide assumes Node.js 20+ and
|
||||
npm are already installed.
|
||||
|
||||
## 1. Fork and clone
|
||||
|
||||
1. Go to <https://github.com/ArnasDon/wacrm> and click **Fork** (top right).
|
||||
2. Clone your fork:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your-username>/wacrm.git
|
||||
cd wacrm
|
||||
```
|
||||
|
||||
## 2. Install dependencies
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## 3. Create the environment file
|
||||
|
||||
Copy the template and fill in the values (full reference in
|
||||
[environment-variables.md](./environment-variables.md)):
|
||||
|
||||
```bash
|
||||
cp .env.local.example .env.local
|
||||
```
|
||||
|
||||
You cannot run `npm run dev` until **at least** `NEXT_PUBLIC_SUPABASE_URL`
|
||||
and `NEXT_PUBLIC_SUPABASE_ANON_KEY` are set. You need the full Supabase
|
||||
setup before WhatsApp features will work, so do that next.
|
||||
|
||||
## 4. Set up Supabase
|
||||
|
||||
Follow [supabase-setup.md](./supabase-setup.md) to create the project and
|
||||
run the migrations. Come back here when the URL, anon key, and service-role
|
||||
key are populated in `.env.local`.
|
||||
|
||||
## 5. Generate the encryption key
|
||||
|
||||
Access tokens for WhatsApp are encrypted at rest with AES-256-CBC. Generate
|
||||
a 64-character hex key:
|
||||
|
||||
```bash
|
||||
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||
```
|
||||
|
||||
Paste the output into `ENCRYPTION_KEY` in `.env.local`. **Do not change
|
||||
this value later** — existing tokens are encrypted with whatever value was
|
||||
set at the time, and rotating it will make them unreadable.
|
||||
|
||||
## 6. Run the dev server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open <http://localhost:3000>. You should see the marketing landing page.
|
||||
|
||||
- Create an account at `/signup`.
|
||||
- After sign-in you land on `/dashboard`.
|
||||
- The inbox, contacts, pipelines, automations, and broadcasts modules are
|
||||
all empty until you connect a WhatsApp number
|
||||
([whatsapp-setup.md](./whatsapp-setup.md)).
|
||||
|
||||
## 7. Commands cheat sheet
|
||||
|
||||
| Command | Purpose |
|
||||
| ---------------- | ---------------------------------------------- |
|
||||
| `npm run dev` | Dev server with Turbopack HMR on `:3000`. |
|
||||
| `npm run build` | Production build. |
|
||||
| `npm start` | Run the production build. |
|
||||
| `npm run lint` | ESLint across the project. |
|
||||
|
||||
## Next step
|
||||
|
||||
[Supabase setup →](./supabase-setup.md)
|
||||
84
docs/supabase-setup.md
Normal file
84
docs/supabase-setup.md
Normal file
@ -0,0 +1,84 @@
|
||||
# Supabase setup
|
||||
|
||||
WaCRM uses Supabase for Postgres, authentication, row-level security (RLS),
|
||||
and (optionally) storage. You need one Supabase project per WaCRM
|
||||
deployment.
|
||||
|
||||
## 1. Create the project
|
||||
|
||||
1. Sign in at <https://supabase.com> and create a **new project**.
|
||||
2. Pick the region closest to your users. Save the database password shown
|
||||
at creation time — you will not see it again.
|
||||
3. Wait for the project to provision (about a minute).
|
||||
|
||||
## 2. Grab your keys
|
||||
|
||||
Open **Project Settings → API** in the Supabase dashboard. Copy:
|
||||
|
||||
- **Project URL** → `NEXT_PUBLIC_SUPABASE_URL`
|
||||
- **anon / public** key → `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
||||
- **service_role** key → `SUPABASE_SERVICE_ROLE_KEY`
|
||||
|
||||
Paste them into `.env.local`.
|
||||
|
||||
> **Do not commit the service-role key.** It bypasses RLS entirely. The
|
||||
> repo's `.gitignore` already excludes `.env.local` — keep it that way.
|
||||
|
||||
## 3. Run the migrations
|
||||
|
||||
All schema changes live in `supabase/migrations/` as plain SQL and are
|
||||
idempotent (safe to re-run). The simplest way to apply them:
|
||||
|
||||
### Option A — SQL Editor (quickest)
|
||||
|
||||
1. Open **SQL Editor** in the Supabase dashboard.
|
||||
2. For each file in `supabase/migrations/`, in numeric order:
|
||||
- `001_initial_schema.sql`
|
||||
- `002_pipelines_enhancements.sql`
|
||||
- `003_broadcast_recipient_wamid.sql`
|
||||
- `004_contact_delete_set_null.sql`
|
||||
- `005_broadcast_counts_incremental.sql`
|
||||
- `006_automations.sql`
|
||||
- `007_automations_increment_counter.sql`
|
||||
3. Paste into the editor and run. Each file prints its own status.
|
||||
|
||||
### Option B — Supabase CLI
|
||||
|
||||
```bash
|
||||
npm install --global supabase
|
||||
supabase login
|
||||
supabase link --project-ref <your-project-ref>
|
||||
supabase db push
|
||||
```
|
||||
|
||||
The CLI applies every file in `supabase/migrations/` on top of the linked
|
||||
project.
|
||||
|
||||
## 4. Verify
|
||||
|
||||
Open **Table Editor** in the Supabase dashboard. You should see tables
|
||||
including `profiles`, `contacts`, `conversations`, `messages`, `pipelines`,
|
||||
`broadcasts`, `automations`, and `whatsapp_config`. If any are missing, a
|
||||
migration failed — re-run it and check the SQL output.
|
||||
|
||||
## 5. Auth settings
|
||||
|
||||
Under **Authentication → Providers**, confirm:
|
||||
|
||||
- **Email** is enabled (default).
|
||||
- **Confirm email** is on for production, off for local if you want
|
||||
frictionless testing.
|
||||
|
||||
Under **Authentication → URL Configuration**, add your production URL
|
||||
(e.g., `https://crm.example.com`) to the allow-list so password-reset
|
||||
emails link back correctly.
|
||||
|
||||
## 6. (Optional) Storage
|
||||
|
||||
WaCRM downloads WhatsApp media through Meta's `/download` endpoint and
|
||||
currently relays it on demand rather than caching it in Supabase Storage.
|
||||
No bucket setup is required for a default install.
|
||||
|
||||
## Next step
|
||||
|
||||
[WhatsApp setup →](./whatsapp-setup.md)
|
||||
118
docs/troubleshooting.md
Normal file
118
docs/troubleshooting.md
Normal file
@ -0,0 +1,118 @@
|
||||
# Troubleshooting
|
||||
|
||||
The greatest hits. If your problem is not here, open an issue at
|
||||
<https://github.com/ArnasDon/wacrm/issues>.
|
||||
|
||||
## Build-time
|
||||
|
||||
### `Error: ENCRYPTION_KEY must be 64 hex chars`
|
||||
|
||||
`ENCRYPTION_KEY` is missing or not the right length. Generate one:
|
||||
|
||||
```bash
|
||||
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||
```
|
||||
|
||||
Put the output into `.env.local` / your production env.
|
||||
|
||||
### `Error: supabaseUrl is required`
|
||||
|
||||
`NEXT_PUBLIC_SUPABASE_URL` or `NEXT_PUBLIC_SUPABASE_ANON_KEY` is not set
|
||||
at build time. On Hostinger / any Node host, make sure the env vars are
|
||||
exported **before** `npm run build` runs.
|
||||
|
||||
### Next.js complains about missing framework docs
|
||||
|
||||
The repo's `AGENTS.md` pins contributors to the docs bundled in
|
||||
`node_modules/next/dist/docs/` — that notice is for humans editing the
|
||||
code, it does not affect your build.
|
||||
|
||||
## Auth
|
||||
|
||||
### Sign-up succeeds but the confirmation email never arrives
|
||||
|
||||
In Supabase → **Authentication → Providers → Email**, either:
|
||||
|
||||
- Configure a custom SMTP provider (recommended for production), or
|
||||
- Temporarily turn off **Confirm email** while testing.
|
||||
|
||||
### Password-reset links point at `localhost:3000` in production
|
||||
|
||||
Set `NEXT_PUBLIC_SITE_URL` **and** add the same origin to Supabase →
|
||||
**Authentication → URL Configuration → Redirect URLs**.
|
||||
|
||||
## WhatsApp
|
||||
|
||||
### Webhook verification fails in Meta
|
||||
|
||||
- The **verify token** in Meta must match exactly what you saved in
|
||||
**Settings → WhatsApp** inside WaCRM.
|
||||
- The callback URL must be reachable without auth. Test it yourself:
|
||||
`curl 'https://crm.example.com/api/whatsapp/webhook?hub.mode=subscribe&hub.verify_token=<token>&hub.challenge=test'`
|
||||
should return `test`.
|
||||
- If you set `META_APP_SECRET`, check the app secret matches — a bad
|
||||
secret causes 401s on inbound webhooks, but verification itself does
|
||||
not use it.
|
||||
|
||||
### Messages go out but nothing comes in
|
||||
|
||||
1. Confirm the webhook is **Subscribed** to `messages` under Meta →
|
||||
WhatsApp → Configuration.
|
||||
2. Confirm the phone number is listed under **Recipients** during testing
|
||||
(test-number apps only deliver to whitelisted testers).
|
||||
3. Check server logs — inbound webhooks hit
|
||||
`POST /api/whatsapp/webhook`. A 200 with no message row means the
|
||||
payload parsed successfully but didn't match any known contact's
|
||||
config — double-check `phone_number_id`.
|
||||
|
||||
### `Token decryption failed`
|
||||
|
||||
`ENCRYPTION_KEY` changed since the token was saved. Reconnect the
|
||||
WhatsApp account from **Settings → WhatsApp** to re-encrypt with the
|
||||
current key.
|
||||
|
||||
## Automations
|
||||
|
||||
### Wait steps never resume
|
||||
|
||||
The cron drain is not running. See
|
||||
[automations-and-cron.md](./automations-and-cron.md).
|
||||
|
||||
Quick sanity check from your machine:
|
||||
|
||||
```bash
|
||||
curl -s -H "x-cron-secret: <secret>" https://crm.example.com/api/automations/cron
|
||||
```
|
||||
|
||||
If that returns `{"processed":N}` with N growing when a wait is due, the
|
||||
endpoint is fine and the problem is just the schedule.
|
||||
|
||||
### An automation fires twice for the same message
|
||||
|
||||
Most likely two WaCRM instances share one Supabase project and both
|
||||
receive the same webhook. The webhook handler deduplicates by Meta's
|
||||
`wamid`, but only within a single deploy — split-brain setups can double
|
||||
up. Either consolidate to one deploy or route the webhook to exactly one.
|
||||
|
||||
## Deploy
|
||||
|
||||
### `502 Bad Gateway` from nginx
|
||||
|
||||
- `pm2 status` — is the `wacrm` process up?
|
||||
- `pm2 logs wacrm` — is the Node process crashing on boot (usually a
|
||||
missing env var)?
|
||||
- `sudo nginx -t` — is the nginx config valid?
|
||||
|
||||
### Meta webhook works until the cert renews
|
||||
|
||||
Certbot renews in-place and reloads nginx. If you see a certificate error
|
||||
right after renewal, restart nginx (`sudo systemctl restart nginx`) and
|
||||
check `/var/log/letsencrypt/letsencrypt.log` for the last renew attempt.
|
||||
|
||||
## Still stuck?
|
||||
|
||||
Open an issue with:
|
||||
|
||||
- Environment (local / Hostinger / other).
|
||||
- The exact error from server logs (`pm2 logs wacrm` or Next's dev output).
|
||||
- What you were trying to do when it happened.
|
||||
104
docs/whatsapp-setup.md
Normal file
104
docs/whatsapp-setup.md
Normal file
@ -0,0 +1,104 @@
|
||||
# WhatsApp setup
|
||||
|
||||
WaCRM talks to the official **WhatsApp Business Cloud API** (Meta). Each
|
||||
account stores its own `phone_number_id`, `waba_id`, and encrypted
|
||||
`access_token` — there is no shared app-level token. This page walks
|
||||
through getting those values and wiring the webhook.
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
- A [Meta for Developers](https://developers.facebook.com) account.
|
||||
- A Meta **Business Manager** account.
|
||||
- A phone number that is **not** already in use on the regular WhatsApp or
|
||||
WhatsApp Business mobile apps. Landlines work; the number must be able
|
||||
to receive an SMS or voice call during verification.
|
||||
|
||||
## 2. Create the Meta app
|
||||
|
||||
1. In Meta for Developers, go to **My Apps → Create App**.
|
||||
2. Pick the **Business** app type.
|
||||
3. On the dashboard, under **Add products**, click **Set up** on
|
||||
**WhatsApp**.
|
||||
4. Connect your Business Manager and accept the terms.
|
||||
|
||||
Meta gives you a **test number** for free. You can use it for local
|
||||
testing, but for production you need to add your own number under
|
||||
**WhatsApp → API Setup → From**.
|
||||
|
||||
## 3. Collect the IDs and the token
|
||||
|
||||
On **WhatsApp → API Setup** you will see:
|
||||
|
||||
| Value | Goes into |
|
||||
| --------------------- | ------------------------------------------------ |
|
||||
| Phone number ID | `phone_number_id` (entered in Settings → Connect) |
|
||||
| WhatsApp Business ID | `waba_id` (optional but recommended) |
|
||||
| Temporary access token | `access_token` (short-lived — see next step) |
|
||||
|
||||
The temporary token expires after 24 hours. For production you must
|
||||
generate a **System User** access token:
|
||||
|
||||
1. **Business Settings → Users → System users → Add**.
|
||||
2. Name it `wacrm-system-user`, role **Admin**.
|
||||
3. Click **Generate new token**, pick the app, and grant:
|
||||
- `whatsapp_business_management`
|
||||
- `whatsapp_business_messaging`
|
||||
4. Copy the token. **This is shown only once.**
|
||||
|
||||
## 4. Connect it inside WaCRM
|
||||
|
||||
1. Run WaCRM locally (or open your deployed instance).
|
||||
2. Sign in, then go to **Settings → WhatsApp**.
|
||||
3. Fill in:
|
||||
- **Phone number ID** — from step 3.
|
||||
- **WhatsApp Business ID** — optional.
|
||||
- **Access token** — the System User token from step 3.
|
||||
- **Verify token** — any random string you make up; you will paste the
|
||||
same value into Meta in the next step.
|
||||
4. Save. WaCRM encrypts the access token and verify token with your
|
||||
`ENCRYPTION_KEY` before writing them to Supabase.
|
||||
|
||||
## 5. Configure the webhook in Meta
|
||||
|
||||
Under **WhatsApp → Configuration → Webhook**:
|
||||
|
||||
- **Callback URL**:
|
||||
- Local dev: run `npx ngrok http 3000` (or similar) and paste
|
||||
`https://<your-subdomain>.ngrok.app/api/whatsapp/webhook`.
|
||||
- Production: `https://<your-domain>/api/whatsapp/webhook`.
|
||||
- **Verify token**: the same string you entered in step 4.
|
||||
- Click **Verify and save**. Meta sends a GET with
|
||||
`hub.challenge` — WaCRM's webhook route decrypts stored verify tokens
|
||||
and echoes the challenge back. If verification fails, double-check the
|
||||
verify token matches and the callback URL is publicly reachable.
|
||||
|
||||
### Subscribe to events
|
||||
|
||||
Under the webhook config, **Subscribe to** at minimum:
|
||||
|
||||
- `messages`
|
||||
- `message_template_status_update`
|
||||
|
||||
`messages` delivers inbound messages and delivery / read statuses;
|
||||
`message_template_status_update` keeps Meta-approved template statuses in
|
||||
sync on the broadcast UI.
|
||||
|
||||
## 6. Signature verification (recommended)
|
||||
|
||||
Set `META_APP_SECRET` to your app's **App Secret** (Meta for Developers →
|
||||
App Settings → Basic). When present, WaCRM validates the `X-Hub-Signature-256`
|
||||
header on every inbound webhook and drops unsigned or forged calls.
|
||||
|
||||
## 7. Send a test message
|
||||
|
||||
1. From Meta's **API Setup** page, send a test message to a number that is
|
||||
a registered tester.
|
||||
2. Watch the WaCRM Inbox — the message should appear within a second or
|
||||
two.
|
||||
3. Reply from WaCRM; the recipient gets a real WhatsApp message.
|
||||
|
||||
If nothing shows up, see [troubleshooting.md](./troubleshooting.md).
|
||||
|
||||
## Next step
|
||||
|
||||
[Environment variables →](./environment-variables.md)
|
||||
Loading…
Reference in New Issue
Block a user