Fixes the 14 pre-existing lint errors surfaced by React 19's new
hook rules so CI can enforce lint on every PR instead of tolerating
failures. The errors split roughly into three camps:
1) react-hooks/refs — "Cannot access refs during render"
4 occurrences of the "latest ref" pattern that assigned
`ref.current = x` during render. Moved each assignment into a
`useEffect(() => { ref.current = x })` — the canonical React-19
pattern. Consumers only read `.current` inside async callbacks
that run after commit, so the very slight delay to the update is
fine.
Touched: src/hooks/use-realtime.ts (onMessageRef,
onConversationRef), src/components/inbox/message-thread.tsx
(onMessagesLoadedRef), src/components/inbox/conversation-list.tsx
(onConversationsLoadedRef).
2) react-hooks/set-state-in-effect — genuine issues
- contacts/page.tsx: the `setPage(0)` on search change moved from
a useEffect into the `onChange` handler of the search input,
which is the cleaner pattern anyway.
- settings/page.tsx: the local `tab` state + sync effect were
removed entirely; the URL query param is now the single source
of truth, and the `onChange` handler just calls
`router.replace(...)`. Simpler and fixes the lint error.
3) react-hooks/set-state-in-effect — false positives for
load-on-mount and prop-driven sync
Suppressed per-call (or per-block for effects with many setters)
with explanatory comments. These effects use setters inside
async Supabase-query callbacks, not synchronously in the effect
body, so the cascade the rule warns about doesn't apply. Files:
contacts/page.tsx, pipelines/page.tsx, pipelines/deal-form.tsx,
pipelines/pipeline-settings.tsx,
components/inbox/contact-sidebar.tsx.
4) react-hooks/preserve-manual-memoization — one useCallback
Rule complained that the inferred dep was `contact` but the
source dep list was `[contact?.phone]`. Broadened the manual dep
to `[contact]` to match — callback behaviour is unchanged (it
still only reads `contact?.phone`), and the React Compiler can
now preserve the memoization.
And:
- .github/workflows/ci.yml: dropped `continue-on-error: true` on
the lint step. Lint now blocks merge on any new error.
Verified: `npm run lint` → 0 errors (24 warnings remain; all
pre-existing unused-import / missing-dep / <img> warnings that don't
fail CI). `npm run typecheck` clean. Landing, /docs, /login, and
/settings redirects all still respond correctly from the dev server.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .github | ||
| docs | ||
| public | ||
| src | ||
| supabase/migrations | ||
| .editorconfig | ||
| .env.local.example | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| components.json | ||
| CONTRIBUTING.md | ||
| eslint.config.mjs | ||
| LICENSE | ||
| next.config.ts | ||
| package-lock.json | ||
| package.json | ||
| postcss.config.mjs | ||
| README.md | ||
| tsconfig.json | ||
WaCRM
Self-hostable WhatsApp CRM template — shared inbox, contacts, sales pipelines, broadcasts, and no-code automations. Fork it, brand it, host it.
What you get out of the box
- Shared inbox on the official WhatsApp Business API — multiple agents working one number, per-conversation assignment, status, and notes.
- Contacts + tags + custom fields, CSV import, deduplication.
- Sales pipelines (Kanban) with deals linked to conversations.
- Broadcasts with Meta-approved templates, delivery + read tracking, per-recipient variable substitution.
- No-code automations — triggers on inbound messages, new contacts, keywords, or schedule; conditional branches, waits, tags, webhooks. Visual builder.
- Real-time dashboard — response times, daily volume, pipeline value, cross-module activity feed.
- Account management — email, password, avatar, global sign-out.
Why fork this?
WaCRM is a template, not a product. Forking means you get:
- Full ownership — your code, your Supabase project, your domain, your data. No SaaS lock-in, no seat pricing, no trust dance.
- Full customisation — add the fields your team needs, remove the modules you don't, redesign anything. The stack is boring on purpose (Next.js + Supabase + Tailwind) so the learning curve is short.
- Zero ops to start — Hostinger Managed Node.js deploys a fork in a few clicks. No Docker, no Kubernetes, no infra team needed.
- Real security primitives — token encryption (AES-256-GCM), RLS on every table, HMAC-verified webhooks, CSP, rate limiting, CI typecheck/build on every PR.
Not a framework. Not an SDK. A concrete, working CRM you can stand up in an afternoon and make yours.
Quick start
# Fork on GitHub first: https://github.com/ArnasDon/wacrm → Fork
git clone https://github.com/<your-username>/wacrm.git
cd wacrm
npm install
cp .env.local.example .env.local # fill in Supabase + Meta creds
npm run dev
Open http://localhost:3000.
Full setup — Supabase migrations, WhatsApp Business API config, and
production deploy — is in docs/.
Documentation
Setup
Deploy
Reference
- Architecture — stack, folder layout, request lifecycle
- Troubleshooting
Stack
- App — Next.js 16 (App Router), React 19, TypeScript, Tailwind v4.
- Data — Supabase (Postgres + Auth + Storage + RLS).
- WhatsApp — Meta Cloud API (official WhatsApp Business API).
Contributing
This is a template, not a collaborative product — the expected flow is
fork → customise → deploy, not upstream contribution. Bug reports
and security issues are welcome; feature PRs often belong in your fork
rather than here. Details in
CONTRIBUTING.md and
.github/SECURITY.md.
License
MIT. Fork it, brand it, host it.