PR 3 of the multi-user accounts series. Lands the server-side endpoints the upcoming Members tab UI will call. Built on the helpers from #169 (`requireRole`, `getCurrentAccount`, `toErrorResponse`). API surface - GET /api/account — caller's account + role - PATCH /api/account — rename (admin+) - GET /api/account/members — roster; email visible to admin+ only - PATCH /api/account/members/[userId] — change role (admin+) - DELETE /api/account/members/[userId] — remove (admin+) - POST /api/account/transfer-ownership — atomic owner handoff (owner) Member-role writes can't ride on the regular `profiles_update` RLS policy (which only allows self-edits — admins can't modify a teammate's row that way). The three SECURITY DEFINER RPCs in the new migration are the scoped escape hatches: - `set_member_role(p_user_id, p_new_role)` — admin+ only. Blocks promotion to / demotion from owner (use transfer instead) and self-targeting. - `remove_account_member(p_user_id)` — admin+ only. Creates a fresh personal account for the removed user and reassigns their profile as its 'owner' — mirror of the signup flow, so they keep their login and just "start over". Blocks removing the owner or self. - `transfer_account_ownership(p_new_owner_user_id)` — owner only. Atomically demotes current owner → admin, promotes target → owner, and points accounts.owner_user_id at the new owner. Demote-first ordering means the temporary "zero owners" state is never visible. Error contract - Each RPC raises with SQLSTATE 42501 (forbidden) or 22023 (bad input) and a human-readable RAISE message. The route handlers map these onto 403 / 400 respectively; anything else collapses to a generic 500. - The TS guards (e.g. `requireRole('owner')` on the transfer route, `isAccountRole(role)` on the PATCH route) are belt-and-braces — they fail fast before the Supabase round trip but the RPCs would catch the same violations regardless. Field visibility - `GET /api/account/members` returns `email` only when the caller is admin+. Agents and viewers see name + avatar + role + joined date — matches the planning decision so a viewer can't harvest the team's email list. Verification - `npm run lint` → 0 errors (same 20 pre-existing warnings) - `npm run typecheck` → clean - `npm test` → 366/366 pass - `npm run build` → succeeds; the 4 new routes register as ƒ (dynamic — they all use `next/headers` cookies via the SSR client) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .github | ||
| public | ||
| src | ||
| supabase/migrations | ||
| .editorconfig | ||
| .env.local.example | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc | ||
| AGENTS.md | ||
| CHANGELOG.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 | ||
| vitest.config.ts | ||
wacrm — CRM Template for WhatsApp
Self-hostable CRM template for WhatsApp® — shared inbox, contacts, sales pipelines, broadcasts, and no-code automations. Fork it, brand it, host it.
The marketing site and self-host docs live in a separate repo: ArnasDon/wacrm-site (wacrm.tech). This repo is the product — clone or fork it to run your own CRM.
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?
This 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. You'll be redirected to /login (or
/dashboard if already signed in).
Documentation
Full self-host documentation — Supabase migrations, WhatsApp Business API config, and production deploy — lives at wacrm.tech/docs (source: ArnasDon/wacrm-site).
Key pages:
- Getting started
- Supabase setup
- WhatsApp setup
- Environment variables
- Deploy on Hostinger
- Architecture
- 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.