Merge remote-tracking branch 'origin/main' into chore/hostinger-accent-palette

# Conflicts:
#	src/app/icon.tsx
#	src/components/docs/shell.tsx
#	src/components/landing/footer.tsx
#	src/components/landing/nav.tsx
This commit is contained in:
Arnas Donauskas 2026-05-06 13:35:46 +03:00
commit 4bb157c705
No known key found for this signature in database
37 changed files with 107 additions and 79 deletions

View File

@ -11,8 +11,8 @@ that standard.
If you witness or experience behaviour that violates the Code, please If you witness or experience behaviour that violates the Code, please
report it privately to the project maintainer: report it privately to the project maintainer:
- Email: **a.donauskas@hostinger.com** with `[WaCRM conduct]` in the - Email: **a.donauskas@hostinger.com** with `[CRM template conduct]` in
subject. the subject.
Reports are handled confidentially. Expect an acknowledgement within Reports are handled confidentially. Expect an acknowledgement within
72 hours and a decision on next steps within a week. 72 hours and a decision on next steps within a week.

View File

@ -1,5 +1,5 @@
name: Bug report name: Bug report
description: Something in WaCRM isn't working the way the docs say it should. description: Something in the template isn't working the way the docs say it should.
title: "[bug] " title: "[bug] "
labels: ["bug", "triage"] labels: ["bug", "triage"]
body: body:

View File

@ -6,6 +6,6 @@ contact_links:
- name: Setup / "how do I..." questions - name: Setup / "how do I..." questions
url: https://github.com/ArnasDon/wacrm/blob/main/docs/README.md url: https://github.com/ArnasDon/wacrm/blob/main/docs/README.md
about: Check the docs first — setup, deploy, troubleshooting are all covered. about: Check the docs first — setup, deploy, troubleshooting are all covered.
- name: Using WaCRM as a template (forking) - name: Using this as a template (forking)
url: https://github.com/ArnasDon/wacrm/blob/main/CONTRIBUTING.md url: https://github.com/ArnasDon/wacrm/blob/main/CONTRIBUTING.md
about: WaCRM is a template. Most changes belong in your fork, not an upstream issue — here's how that works. about: This is a template. Most changes belong in your fork, not an upstream issue — here's how that works.

View File

@ -8,7 +8,7 @@ body:
value: | value: |
Thanks for the idea — but read this first. Thanks for the idea — but read this first.
WaCRM is a **template**, not a collaborative product. The This is a **template**, not a collaborative product. The
upstream scope is intentionally narrow, so most feature upstream scope is intentionally narrow, so most feature
requests end up as *"build this in your fork"* rather than requests end up as *"build this in your fork"* rather than
landing here. That's the point of a template. landing here. That's the point of a template.
@ -29,7 +29,7 @@ body:
id: problem id: problem
attributes: attributes:
label: What's the problem? label: What's the problem?
description: What are you trying to do today that WaCRM makes harder than it should? description: What are you trying to do today that the template makes harder than it should?
placeholder: | placeholder: |
When a broadcast ends I have no way to see which recipients When a broadcast ends I have no way to see which recipients
didn't reply so I can follow up manually. didn't reply so I can follow up manually.

6
.github/SECURITY.md vendored
View File

@ -1,6 +1,6 @@
# Security Policy # Security Policy
Thanks for taking the time to look into WaCRM's security. Thanks for taking the time to look into the security of this template.
## Reporting a vulnerability ## Reporting a vulnerability
@ -12,7 +12,7 @@ Instead, please report privately via one of:
- [GitHub Security Advisories](https://github.com/ArnasDon/wacrm/security/advisories/new) - [GitHub Security Advisories](https://github.com/ArnasDon/wacrm/security/advisories/new)
(preferred — keeps the disclosure, fix, and CVE all in one place). (preferred — keeps the disclosure, fix, and CVE all in one place).
- Email: `a.donauskas@hostinger.com` with `[WaCRM security]` in the subject. - Email: `a.donauskas@hostinger.com` with `[CRM template security]` in the subject.
Include, if you can: Include, if you can:
@ -59,4 +59,4 @@ action against anyone who:
- Gives us reasonable time to respond before any public disclosure. - Gives us reasonable time to respond before any public disclosure.
- Doesn't exploit the issue beyond what's necessary to demonstrate it. - Doesn't exploit the issue beyond what's necessary to demonstrate it.
Thanks for helping keep WaCRM (and its forks) safe. Thanks for helping keep this template (and its forks) safe.

View File

@ -1,5 +1,5 @@
<!-- <!--
Heads up: WaCRM is a template, not a collaborative product. Most Heads up: this is a template, not a collaborative product. Most
changes belong in your fork. See CONTRIBUTING.md for which kinds of changes belong in your fork. See CONTRIBUTING.md for which kinds of
upstream PRs tend to land (security, correctness, docs) vs. which upstream PRs tend to land (security, correctness, docs) vs. which
belong in a fork (new features, stack swaps, opinionated refactors). belong in a fork (new features, stack swaps, opinionated refactors).

View File

@ -1,6 +1,6 @@
# Using WaCRM # Using this template
WaCRM is a **template repository**, not a collaborative product. The This is a **template repository**, not a collaborative product. The
expected flow is: expected flow is:
1. **Fork** it to your own GitHub account or organisation. 1. **Fork** it to your own GitHub account or organisation.
@ -95,9 +95,9 @@ closed — open the issue first to align.
## If you maintain a public fork ## If you maintain a public fork
- Rebrand. The WaCRM name, favicon, and `wacrm.tech` URL belong to the - Rebrand. The "CRM Template for WhatsApp" name, favicon, and
upstream project; please swap them for your own before putting your `wacrm.tech` URL belong to the upstream project; please swap them
deployment in front of users. for your own before putting your deployment in front of users.
- Keep the MIT [`LICENSE`](./LICENSE) file — that's how the template's - Keep the MIT [`LICENSE`](./LICENSE) file — that's how the template's
permissions travel with the code. Attribution in a `README` section permissions travel with the code. Attribution in a `README` section
is appreciated but not required. is appreciated but not required.

View File

@ -1,8 +1,8 @@
# WaCRM # CRM Template for WhatsApp
> Self-hostable WhatsApp CRM template — shared inbox, contacts, sales > Self-hostable CRM template for WhatsApp — shared inbox, contacts,
> pipelines, broadcasts, and no-code automations. Fork it, brand it, > sales pipelines, broadcasts, and no-code automations. Fork it, brand
> host it. > it, host it.
[![License: MIT](https://img.shields.io/badge/License-MIT-violet.svg)](./LICENSE) [![License: MIT](https://img.shields.io/badge/License-MIT-violet.svg)](./LICENSE)
[![CI](https://github.com/ArnasDon/wacrm/actions/workflows/ci.yml/badge.svg)](https://github.com/ArnasDon/wacrm/actions/workflows/ci.yml) [![CI](https://github.com/ArnasDon/wacrm/actions/workflows/ci.yml/badge.svg)](https://github.com/ArnasDon/wacrm/actions/workflows/ci.yml)
@ -28,7 +28,7 @@
## Why fork this? ## Why fork this?
WaCRM is a **template**, not a product. Forking means you get: This is a **template**, not a product. Forking means you get:
- **Full ownership** — your code, your Supabase project, your domain, - **Full ownership** — your code, your Supabase project, your domain,
your data. No SaaS lock-in, no seat pricing, no trust dance. your data. No SaaS lock-in, no seat pricing, no trust dance.

View File

@ -1,7 +1,7 @@
# WaCRM documentation # Documentation
WaCRM is a self-hostable WhatsApp CRM built on Next.js and Supabase. These A self-hostable CRM template for WhatsApp built on Next.js and Supabase.
docs walk you from a freshly forked repo to a production deploy. These docs walk you from a freshly forked repo to a production deploy.
## Reading order ## Reading order

View File

@ -1,6 +1,6 @@
# Automations cron # Automations cron
WaCRM's **Automations** module lets you build flows that react to WhatsApp The **Automations** module lets you build flows that react to WhatsApp
events (new message, new contact, keyword match, schedule, etc.). Most events (new message, new contact, keyword match, schedule, etc.). Most
steps run inline — the exception is the **Wait** step, which parks the steps run inline — the exception is the **Wait** step, which parks the
execution in `automation_pending_executions` until its due time. execution in `automation_pending_executions` until its due time.

View File

@ -1,7 +1,7 @@
# Deploy on Hostinger # Deploy on Hostinger
Hostinger's **[Managed Node.js Hosting](https://www.hostinger.com/web-apps-hosting)** Hostinger's **[Managed Node.js Hosting](https://www.hostinger.com/web-apps-hosting)**
is the recommended way to run WaCRM in production: Hostinger patches the is the recommended way to run this template in production: Hostinger patches the
OS and the Node runtime, handles SSL, and gives you a Git-based deploy OS and the Node runtime, handles SSL, and gives you a Git-based deploy
flow from hPanel. You deploy from your fork without ever opening an SSH flow from hPanel. You deploy from your fork without ever opening an SSH
session if you don't want to. session if you don't want to.
@ -93,7 +93,7 @@ baked into the client bundle.
From the app page, click **Restart application** (or run the equivalent From the app page, click **Restart application** (or run the equivalent
from the terminal). hPanel boots `npm start` behind its own reverse proxy from the terminal). hPanel boots `npm start` behind its own reverse proxy
on the domain you configured. Hit the URL in a browser — you should land on the domain you configured. Hit the URL in a browser — you should land
on the WaCRM marketing page. on the marketing page.
SSL is provisioned automatically. If you used a subdomain, Hostinger's SSL is provisioned automatically. If you used a subdomain, Hostinger's
AutoSSL usually takes a minute or two; until then the site may serve the AutoSSL usually takes a minute or two; until then the site may serve the
@ -139,7 +139,7 @@ idempotent.
## When to reach for a VPS instead ## When to reach for a VPS instead
Managed Node.js covers most WaCRM deploys. Consider Managed Node.js covers most deploys of this template. Consider
[Hostinger VPS](https://www.hostinger.com/vps-hosting) if you need: [Hostinger VPS](https://www.hostinger.com/vps-hosting) if you need:
- Long-running background workers beyond what the single Next.js process - Long-running background workers beyond what the single Next.js process

View File

@ -1,6 +1,6 @@
# Getting started # Getting started
Run WaCRM locally in about 15 minutes. This guide assumes Node.js 20+ and Run the template locally in about 15 minutes. This guide assumes Node.js 20+ and
npm are already installed. npm are already installed.
## 1. Fork and clone ## 1. Fork and clone

View File

@ -1,8 +1,7 @@
# Supabase setup # Supabase setup
WaCRM uses Supabase for Postgres, authentication, row-level security (RLS), This template uses Supabase for Postgres, authentication, row-level security (RLS),
and (optionally) storage. You need one Supabase project per WaCRM and (optionally) storage. You need one Supabase project per deployment.
deployment.
## 1. Create the project ## 1. Create the project
@ -75,7 +74,7 @@ emails link back correctly.
## 6. (Optional) Storage ## 6. (Optional) Storage
WaCRM downloads WhatsApp media through Meta's `/download` endpoint and The app downloads WhatsApp media through Meta's `/download` endpoint and
currently relays it on demand rather than caching it in Supabase Storage. currently relays it on demand rather than caching it in Supabase Storage.
No bucket setup is required for a default install. No bucket setup is required for a default install.

View File

@ -46,7 +46,7 @@ Set `NEXT_PUBLIC_SITE_URL` **and** add the same origin to Supabase →
### Webhook verification fails in Meta ### Webhook verification fails in Meta
- The **verify token** in Meta must match exactly what you saved in - The **verify token** in Meta must match exactly what you saved in
**Settings → WhatsApp** inside WaCRM. **Settings → WhatsApp** inside the app.
- The callback URL must be reachable without auth. Test it yourself: - 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'` `curl 'https://crm.example.com/api/whatsapp/webhook?hub.mode=subscribe&hub.verify_token=<token>&hub.challenge=test'`
should return `test`. should return `test`.
@ -91,7 +91,7 @@ endpoint is fine and the problem is just the schedule.
### An automation fires twice for the same message ### An automation fires twice for the same message
Most likely two WaCRM instances share one Supabase project and both Most likely two app instances share one Supabase project and both
receive the same webhook. The webhook handler deduplicates by Meta's receive the same webhook. The webhook handler deduplicates by Meta's
`wamid`, but only within a single deploy — split-brain setups can double `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. up. Either consolidate to one deploy or route the webhook to exactly one.

View File

@ -1,6 +1,6 @@
# WhatsApp setup # WhatsApp setup
WaCRM talks to the official **WhatsApp Business Cloud API** (Meta). Each This template talks to the official **WhatsApp Business Cloud API** (Meta). Each
account stores its own `phone_number_id`, `waba_id`, and encrypted account stores its own `phone_number_id`, `waba_id`, and encrypted
`access_token` — there is no shared app-level token. This page walks `access_token` — there is no shared app-level token. This page walks
through getting those values and wiring the webhook. through getting those values and wiring the webhook.
@ -45,9 +45,9 @@ generate a **System User** access token:
- `whatsapp_business_messaging` - `whatsapp_business_messaging`
4. Copy the token. **This is shown only once.** 4. Copy the token. **This is shown only once.**
## 4. Connect it inside WaCRM ## 4. Connect it inside the app
1. Run WaCRM locally (or open your deployed instance). 1. Run the app locally (or open your deployed instance).
2. Sign in, then go to **Settings → WhatsApp**. 2. Sign in, then go to **Settings → WhatsApp**.
3. Fill in: 3. Fill in:
- **Phone number ID** — from step 3. - **Phone number ID** — from step 3.
@ -55,7 +55,7 @@ generate a **System User** access token:
- **Access token** — the System User token from step 3. - **Access token** — the System User token from step 3.
- **Verify token** — any random string you make up; you will paste the - **Verify token** — any random string you make up; you will paste the
same value into Meta in the next step. same value into Meta in the next step.
4. Save. WaCRM encrypts the access token and verify token with your 4. Save. The app encrypts the access token and verify token with your
`ENCRYPTION_KEY` before writing them to Supabase. `ENCRYPTION_KEY` before writing them to Supabase.
## 5. Configure the webhook in Meta ## 5. Configure the webhook in Meta
@ -68,7 +68,7 @@ Under **WhatsApp → Configuration → Webhook**:
- Production: `https://<your-domain>/api/whatsapp/webhook`. - Production: `https://<your-domain>/api/whatsapp/webhook`.
- **Verify token**: the same string you entered in step 4. - **Verify token**: the same string you entered in step 4.
- Click **Verify and save**. Meta sends a GET with - Click **Verify and save**. Meta sends a GET with
`hub.challenge` — WaCRM's webhook route decrypts stored verify tokens `hub.challenge` — the app's webhook route decrypts stored verify tokens
and echoes the challenge back. If verification fails, double-check the and echoes the challenge back. If verification fails, double-check the
verify token matches and the callback URL is publicly reachable. verify token matches and the callback URL is publicly reachable.
@ -86,7 +86,7 @@ sync on the broadcast UI.
## 6. Signature verification (required) ## 6. Signature verification (required)
Set `META_APP_SECRET` to your app's **App Secret** (Meta for Developers → Set `META_APP_SECRET` to your app's **App Secret** (Meta for Developers →
App Settings → Basic). WaCRM validates the `X-Hub-Signature-256` HMAC App Settings → Basic). The app validates the `X-Hub-Signature-256` HMAC
on every inbound webhook and **rejects every request if the env var is on every inbound webhook and **rejects every request if the env var is
not set** — anyone who knew the webhook URL could otherwise spoof not set** — anyone who knew the webhook URL could otherwise spoof
messages and status updates. Configure it before pointing the webhook messages and status updates. Configure it before pointing the webhook
@ -96,9 +96,8 @@ at a deployed instance.
1. From Meta's **API Setup** page, send a test message to a number that is 1. From Meta's **API Setup** page, send a test message to a number that is
a registered tester. a registered tester.
2. Watch the WaCRM Inbox — the message should appear within a second or 2. Watch the Inbox — the message should appear within a second or two.
two. 3. Reply from the app; the recipient gets a real WhatsApp message.
3. Reply from WaCRM; the recipient gets a real WhatsApp message.
If nothing shows up, see [troubleshooting.md](./troubleshooting.md). If nothing shows up, see [troubleshooting.md](./troubleshooting.md).

View File

@ -2,7 +2,7 @@
"name": "wacrm", "name": "wacrm",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"description": "Self-hostable WhatsApp CRM built on Next.js and Supabase — shared inbox, contacts, sales pipelines, broadcasts, and no-code automations.", "description": "Self-hostable CRM template for WhatsApp built on Next.js and Supabase — shared inbox, contacts, sales pipelines, broadcasts, and no-code automations.",
"license": "MIT", "license": "MIT",
"author": "Arnas Donauskas", "author": "Arnas Donauskas",
"homepage": "https://wacrm.tech", "homepage": "https://wacrm.tech",

View File

@ -52,7 +52,7 @@ export default function LoginPage() {
</div> </div>
<CardTitle className="text-xl text-white">Welcome back</CardTitle> <CardTitle className="text-xl text-white">Welcome back</CardTitle>
<CardDescription className="text-slate-400"> <CardDescription className="text-slate-400">
Sign in to your WaCRM account Sign in to your account
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>

View File

@ -102,7 +102,7 @@ export default function SignupPage() {
</div> </div>
<CardTitle className="text-xl text-white">Create account</CardTitle> <CardTitle className="text-xl text-white">Create account</CardTitle>
<CardDescription className="text-slate-400"> <CardDescription className="text-slate-400">
Get started with WaCRM Get started with CRM Template for WhatsApp
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>

View File

@ -11,11 +11,11 @@ import { decrypt } from '@/lib/whatsapp/encryption'
* template locally, try to broadcast with it, and hit Meta's error * template locally, try to broadcast with it, and hit Meta's error
* #132001 "Template name does not exist in the translation" — because * #132001 "Template name does not exist in the translation" — because
* Meta had never seen the template, or had it approved under a * Meta had never seen the template, or had it approved under a
* different language code than what WaCRM stored. * different language code than what we stored locally.
* *
* This route pulls the source of truth (Meta's approved templates) * This route pulls the source of truth (Meta's approved templates)
* and upserts them into the local catalog by (user_id, name, language). * and upserts them into the local catalog by (user_id, name, language).
* After a sync, every template row in WaCRM is guaranteed to match * After a sync, every local template row is guaranteed to match
* something Meta will actually accept on send. * something Meta will actually accept on send.
* *
* Scope: * Scope:

View File

@ -3,9 +3,12 @@ import { DocsShell } from '@/components/docs/shell'
import { listDocs } from '@/lib/docs/content' import { listDocs } from '@/lib/docs/content'
export const metadata: Metadata = { export const metadata: Metadata = {
title: { template: '%s — WaCRM Docs', default: 'WaCRM Docs' }, title: {
template: '%s — CRM Template for WhatsApp Docs',
default: 'CRM Template for WhatsApp Docs',
},
description: description:
'Setup, configuration, and deployment docs for the WaCRM template.', 'Setup, configuration, and deployment docs for the CRM Template for WhatsApp.',
} }
export default async function DocsLayout({ export default async function DocsLayout({

View File

@ -16,7 +16,7 @@ export default async function DocsIndexPage() {
Documentation Documentation
</p> </p>
<h1 className="mt-2 text-3xl font-bold tracking-tight text-white sm:text-4xl"> <h1 className="mt-2 text-3xl font-bold tracking-tight text-white sm:text-4xl">
Self-host WaCRM end to end Self-host the CRM template for WhatsApp end to end
</h1> </h1>
<p className="mt-4 text-base leading-relaxed text-slate-400"> <p className="mt-4 text-base leading-relaxed text-slate-400">
Everything you need to take the template from a fresh fork to a Everything you need to take the template from a fresh fork to a

View File

@ -5,7 +5,7 @@ import { SITE_URL } from '@/lib/seo/site-config'
* robots.txt served at /robots.txt. We explicitly disallow every * robots.txt served at /robots.txt. We explicitly disallow every
* gated area so crawlers don't spend their budget on pages they'll * gated area so crawlers don't spend their budget on pages they'll
* bounce off. Auth pages are closed off too — no SEO value, and * bounce off. Auth pages are closed off too — no SEO value, and
* we don't want "Sign in to WaCRM" competing with the landing page * we don't want a "Sign in" page competing with the landing page
* in SERPs. * in SERPs.
*/ */
export default function robots(): MetadataRoute.Robots { export default function robots(): MetadataRoute.Robots {

View File

@ -32,11 +32,17 @@ export function DocsShell({ pages, children }: DocsShellProps) {
> >
{mobileOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />} {mobileOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
</button> </button>
<Link href="/" className="flex items-center gap-2" aria-label="WaCRM home"> <Link
href="/"
className="flex items-center gap-2"
aria-label="CRM Template for WhatsApp home"
>
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-violet-500"> <span className="flex h-8 w-8 items-center justify-center rounded-lg bg-violet-500">
<MessageSquare className="h-4 w-4 text-white" /> <MessageSquare className="h-4 w-4 text-white" />
</span> </span>
<span className="text-lg font-semibold text-white">WaCRM</span> <span className="text-sm font-semibold text-white">
CRM Template for WhatsApp
</span>
<span className="hidden rounded-md border border-slate-700 bg-slate-900 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-slate-400 sm:inline-block"> <span className="hidden rounded-md border border-slate-700 bg-slate-900 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-slate-400 sm:inline-block">
Docs Docs
</span> </span>

View File

@ -70,7 +70,7 @@ export function FeaturesGrid() {
<SectionHeader <SectionHeader
eyebrow="Everything you need" eyebrow="Everything you need"
title="One toolkit for your WhatsApp business" title="One toolkit for your WhatsApp business"
description="Stop stitching together an inbox, a spreadsheet, and a broadcast tool. WaCRM brings them together — and talks to WhatsApp natively." description="Stop stitching together an inbox, a spreadsheet, and a broadcast tool. This CRM template for WhatsApp brings them together — and talks to WhatsApp natively."
/> />
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3"> <div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">

View File

@ -7,11 +7,17 @@ export function Footer() {
<footer className="border-t border-slate-800 bg-slate-950"> <footer className="border-t border-slate-800 bg-slate-950">
<div className="mx-auto grid w-full max-w-7xl grid-cols-2 gap-8 px-6 py-12 sm:grid-cols-5"> <div className="mx-auto grid w-full max-w-7xl grid-cols-2 gap-8 px-6 py-12 sm:grid-cols-5">
<div className="col-span-2 sm:col-span-2"> <div className="col-span-2 sm:col-span-2">
<Link href="/" className="flex items-center gap-2" aria-label="WaCRM home"> <Link
href="/"
className="flex items-center gap-2"
aria-label="CRM Template for WhatsApp home"
>
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-violet-500"> <span className="flex h-8 w-8 items-center justify-center rounded-lg bg-violet-500">
<MessageSquare className="h-4 w-4 text-white" /> <MessageSquare className="h-4 w-4 text-white" />
</span> </span>
<span className="text-lg font-semibold text-white">WaCRM</span> <span className="text-sm font-semibold text-white">
CRM Template for WhatsApp
</span>
</Link> </Link>
<p className="mt-3 max-w-sm text-sm text-slate-500"> <p className="mt-3 max-w-sm text-sm text-slate-500">
One toolkit for your WhatsApp business — shared inbox, pipelines, One toolkit for your WhatsApp business — shared inbox, pipelines,
@ -58,7 +64,7 @@ export function Footer() {
<div className="border-t border-slate-900"> <div className="border-t border-slate-900">
<div className="mx-auto flex w-full max-w-7xl flex-col items-start justify-between gap-3 px-6 py-5 text-xs text-slate-500 sm:flex-row sm:items-center"> <div className="mx-auto flex w-full max-w-7xl flex-col items-start justify-between gap-3 px-6 py-5 text-xs text-slate-500 sm:flex-row sm:items-center">
<span>© {year} WaCRM. All rights reserved.</span> <span>© {year} CRM Template for WhatsApp. All rights reserved.</span>
<span>Built on the official WhatsApp Business API.</span> <span>Built on the official WhatsApp Business API.</span>
</div> </div>
</div> </div>

View File

@ -27,7 +27,9 @@ export function AnalyticsMock() {
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="ml-3 text-[10px] text-slate-500">Dashboard — WaCRM</span> <span className="ml-3 text-[10px] text-slate-500">
Dashboard — CRM Template for WhatsApp
</span>
</div> </div>
<div className="space-y-3 p-4"> <div className="space-y-3 p-4">

View File

@ -47,7 +47,9 @@ export function AutomationMock() {
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="ml-3 text-[10px] text-slate-500">Automations — WaCRM</span> <span className="ml-3 text-[10px] text-slate-500">
Automations — CRM Template for WhatsApp
</span>
</div> </div>
{/* Dotted canvas — matches the real flow builder's background. */} {/* Dotted canvas — matches the real flow builder's background. */}

View File

@ -14,7 +14,9 @@ export function InboxMock() {
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="ml-3 text-[10px] text-slate-500">Inbox — WaCRM</span> <span className="ml-3 text-[10px] text-slate-500">
Inbox — CRM Template for WhatsApp
</span>
</div> </div>
<div className="grid grid-cols-[180px_1fr] lg:grid-cols-[220px_1fr]"> <div className="grid grid-cols-[180px_1fr] lg:grid-cols-[220px_1fr]">

View File

@ -34,7 +34,9 @@ export function PipelineMock() {
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="h-2.5 w-2.5 rounded-full bg-slate-700" /> <span className="h-2.5 w-2.5 rounded-full bg-slate-700" />
<span className="ml-3 text-[10px] text-slate-500">Pipelines — WaCRM</span> <span className="ml-3 text-[10px] text-slate-500">
Pipelines — CRM Template for WhatsApp
</span>
</div> </div>
<div className="grid grid-cols-3 gap-3 p-4"> <div className="grid grid-cols-3 gap-3 p-4">

View File

@ -60,11 +60,17 @@ export function LandingNav() {
)} )}
> >
<div className="mx-auto flex h-16 w-full max-w-7xl items-center justify-between px-6"> <div className="mx-auto flex h-16 w-full max-w-7xl items-center justify-between px-6">
<Link href="/" className="flex items-center gap-2" aria-label="WaCRM home"> <Link
href="/"
className="flex items-center gap-2"
aria-label="CRM Template for WhatsApp home"
>
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-violet-500"> <span className="flex h-8 w-8 items-center justify-center rounded-lg bg-violet-500">
<MessageSquare className="h-4 w-4 text-white" /> <MessageSquare className="h-4 w-4 text-white" />
</span> </span>
<span className="text-lg font-semibold text-white">WaCRM</span> <span className="text-sm font-semibold text-white">
CRM Template for WhatsApp
</span>
</Link> </Link>
<nav className="hidden items-center gap-8 md:flex"> <nav className="hidden items-center gap-8 md:flex">

View File

@ -12,7 +12,7 @@ export function OpenSource() {
<SectionHeader <SectionHeader
eyebrow="Open source" eyebrow="Open source"
title="Fork it, brand it, host it" title="Fork it, brand it, host it"
description="WaCRM is a template you can take and make your own. Grab the source on GitHub and self-host — we recommend Hostinger Managed Node.js Hosting for a zero-ops deploy." description="This CRM template for WhatsApp is a template you can take and make your own. Grab the source on GitHub and self-host — we recommend Hostinger Managed Node.js Hosting for a zero-ops deploy."
/> />
<div className="mx-auto grid max-w-5xl grid-cols-1 gap-5 md:grid-cols-2"> <div className="mx-auto grid max-w-5xl grid-cols-1 gap-5 md:grid-cols-2">
@ -55,7 +55,7 @@ export function OpenSource() {
</h3> </h3>
<p className="mt-1.5 text-sm leading-relaxed text-slate-400"> <p className="mt-1.5 text-sm leading-relaxed text-slate-400">
Best fit for this template — connect your forked repo to Best fit for this template — connect your forked repo to
Managed Node.js Hosting and WaCRM is live in a few minutes. No Managed Node.js Hosting and your CRM is live in a few minutes. No
servers to patch. servers to patch.
</p> </p>
<span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-violet-400 transition-colors group-hover:text-violet-300"> <span className="mt-5 inline-flex items-center gap-1.5 text-sm font-medium text-violet-400 transition-colors group-hover:text-violet-300">

View File

@ -114,7 +114,9 @@ export function Sidebar({ open = false, onClose }: SidebarProps) {
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-violet-500"> <div className="flex h-8 w-8 items-center justify-center rounded-lg bg-violet-500">
<MessageSquare className="h-4 w-4 text-white" /> <MessageSquare className="h-4 w-4 text-white" />
</div> </div>
<span className="text-lg font-semibold text-white">WaCRM</span> <span className="text-sm font-semibold text-white">
CRM Template for WhatsApp
</span>
</Link> </Link>
<button <button
type="button" type="button"

View File

@ -214,7 +214,7 @@ export function ProfileForm() {
<CardHeader> <CardHeader>
<CardTitle className="text-white">Profile</CardTitle> <CardTitle className="text-white">Profile</CardTitle>
<CardDescription className="text-slate-400"> <CardDescription className="text-slate-400">
How you show up across WaCRM. Your avatar and name appear in the How you show up across the app. Your avatar and name appear in the
header, sidebar, and anywhere your teammates see you. header, sidebar, and anywhere your teammates see you.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>

View File

@ -56,9 +56,8 @@ export function SessionsCard() {
Active sessions Active sessions
</CardTitle> </CardTitle>
<CardDescription className="text-slate-400"> <CardDescription className="text-slate-400">
Sign out of every device where you&apos;re logged in to WaCRM — Sign out of every device where you&apos;re logged in — including
including this one. Useful if you lost a laptop or shared your this one. Useful if you lost a laptop or shared your password.
password.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>

View File

@ -22,7 +22,7 @@ const ORDER: Record<string, { order: number; section: string; description: strin
'getting-started': { 'getting-started': {
order: 1, order: 1,
section: 'Setup', section: 'Setup',
description: 'Fork, install, run WaCRM locally in about 15 minutes.', description: 'Fork, install, run the template locally in about 15 minutes.',
}, },
'supabase-setup': { 'supabase-setup': {
order: 2, order: 2,
@ -37,12 +37,12 @@ const ORDER: Record<string, { order: number; section: string; description: strin
'environment-variables': { 'environment-variables': {
order: 4, order: 4,
section: 'Setup', section: 'Setup',
description: 'Full reference for every env var WaCRM reads.', description: 'Full reference for every env var the app reads.',
}, },
'deployment-hostinger': { 'deployment-hostinger': {
order: 5, order: 5,
section: 'Deploy', section: 'Deploy',
description: 'Ship WaCRM on Hostinger Managed Node.js Hosting.', description: 'Ship the template on Hostinger Managed Node.js Hosting.',
}, },
'automations-and-cron': { 'automations-and-cron': {
order: 6, order: 6,

View File

@ -11,7 +11,7 @@ export interface FaqItem {
export const FAQ_ITEMS: FaqItem[] = [ export const FAQ_ITEMS: FaqItem[] = [
{ {
q: 'Do I need my own WhatsApp Business API access?', q: 'Do I need my own WhatsApp Business API access?',
a: 'Yes. WaCRM plugs into your existing Meta WhatsApp Business setup — you bring the phone number and access token, we provide the CRM tooling around it. Any Meta-approved BSP (Business Solution Provider) works.', a: 'Yes. This CRM template for WhatsApp plugs into your existing Meta WhatsApp Business setup — you bring the phone number and access token, we provide the CRM tooling around it. Any Meta-approved BSP (Business Solution Provider) works.',
}, },
{ {
q: 'Can my whole team share one WhatsApp number?', q: 'Can my whole team share one WhatsApp number?',

View File

@ -9,13 +9,13 @@
export const SITE_URL = export const SITE_URL =
process.env.NEXT_PUBLIC_SITE_URL?.replace(/\/$/, '') || 'https://wacrm.tech' process.env.NEXT_PUBLIC_SITE_URL?.replace(/\/$/, '') || 'https://wacrm.tech'
export const SITE_NAME = 'WaCRM' export const SITE_NAME = 'CRM Template for WhatsApp'
export const SITE_TAGLINE = 'Run your WhatsApp business from one inbox' export const SITE_TAGLINE = 'Run your WhatsApp business from one inbox'
/** Default description — reused by layout metadata and structured data. */ /** Default description — reused by layout metadata and structured data. */
export const SITE_DESCRIPTION = export const SITE_DESCRIPTION =
'WaCRM is a WhatsApp CRM for small teams: shared inbox, contact hub, sales pipelines, broadcasts, and no-code automations — built on the official WhatsApp Business API.' 'A CRM template for WhatsApp built for small teams: shared inbox, contact hub, sales pipelines, broadcasts, and no-code automations — built on the official WhatsApp Business API.'
/** /**
* Keyword targets. Search engines largely ignore the meta keywords * Keyword targets. Search engines largely ignore the meta keywords
@ -40,7 +40,7 @@ export const OG_IMAGE_ALT = `${SITE_NAME} — ${SITE_TAGLINE}`
/** Organization info surfaced in JSON-LD. */ /** Organization info surfaced in JSON-LD. */
export const ORG_INFO = { export const ORG_INFO = {
name: SITE_NAME, name: SITE_NAME,
legalName: 'WaCRM', legalName: 'CRM Template for WhatsApp',
url: SITE_URL, url: SITE_URL,
logo: `${SITE_URL}/icon`, logo: `${SITE_URL}/icon`,
} }