mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 17:29:45 +00:00
docs: README polish + architecture + alt hosts
Finishes the template-readiness sequence. All docs — nothing runtime.
README.md
Rewrites the landing page of the repo to actually sell what it is
to someone finding the repo cold on GitHub search.
- Shields.io badges: MIT, CI status, Next.js 16, Supabase, GitHub
stars.
- "What you get out of the box" bullet list — inbox, contacts,
pipelines, broadcasts, automations, dashboard, account
management — so the feature surface is visible before the reader
scrolls.
- "Why fork this?" section: full ownership, full customisation,
zero ops to start, real security primitives. Frames WaCRM as a
template, not an SDK.
- Docs section reorganised into Setup / Deploy / Reference to
match the in-app /docs viewer and docs/README.md.
- Contributing section rewrites the stale "Pull requests welcome"
line to match the fork-first framing from PR #73.
docs/architecture.md (new)
One-page tour for forkers: stack table, full folder layout,
two ASCII request-lifecycle diagrams (inbound webhook + outbound
send), security primitives rundown, and a "where to change things"
index that maps common customisation tasks to source files. This
is the thing I wish I'd had the first time I opened a forked
template.
docs/deployment-alternatives.md (new)
Short blocks for Vercel, Railway, raw VPS, and Docker. Each covers
env-var setup, cron strategy (Vercel cron without custom headers
is a footgun worth calling out), and trade-offs. Keeps Hostinger
as the primary recommendation — this page is for people whose
constraints rule it out.
docs/README.md
- Reading order grouped as Setup / Deploy / Reference, adding the
two new pages.
- Stack-at-a-glance updated: encryption is AES-256-GCM, not CBC
(the PR #71 change that earlier docs hadn't caught up to).
src/lib/docs/content.ts
Registers the two new markdown files in the ORDER map so they
appear in the in-app /docs sidebar under the Reference section,
with prev/next pagination wiring.
Verified: /docs, /docs/architecture, /docs/deployment-alternatives,
and /docs/getting-started all return 200 from the dev server.
Sidebar shows 9 pages grouped Setup / Deploy / Reference with the
new entries. Typecheck clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9c25971c27
commit
7cd0f46369
79
README.md
79
README.md
@ -1,43 +1,100 @@
|
||||
# WaCRM
|
||||
|
||||
Self-hostable WhatsApp CRM — shared inbox, contacts, sales pipelines,
|
||||
broadcasts, and no-code automations — built on Next.js 16 and Supabase.
|
||||
> Self-hostable WhatsApp CRM template — shared inbox, contacts, sales
|
||||
> pipelines, broadcasts, and no-code automations. Fork it, brand it,
|
||||
> host it.
|
||||
|
||||
- **Live demo / marketing site**: [`/`](./src/app/page.tsx)
|
||||
- **Source**: <https://github.com/ArnasDon/wacrm>
|
||||
[](./LICENSE)
|
||||
[](https://github.com/ArnasDon/wacrm/actions/workflows/ci.yml)
|
||||
[](https://nextjs.org)
|
||||
[](https://supabase.com)
|
||||
[](https://github.com/ArnasDon/wacrm/stargazers)
|
||||
|
||||
## 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
|
||||
|
||||
```bash
|
||||
# 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 keys + ENCRYPTION_KEY, then:
|
||||
cp .env.local.example .env.local # fill in Supabase + Meta creds
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open <http://localhost:3000>.
|
||||
|
||||
For the full setup — Supabase migrations, WhatsApp Business API config,
|
||||
production deploy on Hostinger — see [`docs/`](./docs/README.md).
|
||||
Full setup — Supabase migrations, WhatsApp Business API config, and
|
||||
production deploy — is in [`docs/`](./docs/README.md).
|
||||
|
||||
## Documentation
|
||||
|
||||
**Setup**
|
||||
- [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)
|
||||
|
||||
**Deploy**
|
||||
- [Deploy on Hostinger](./docs/deployment-hostinger.md) *(recommended)*
|
||||
- [Alternative hosts](./docs/deployment-alternatives.md) — Vercel,
|
||||
Railway, raw VPS
|
||||
- [Automations cron](./docs/automations-and-cron.md)
|
||||
|
||||
**Reference**
|
||||
- [Architecture](./docs/architecture.md) — stack, folder layout,
|
||||
request lifecycle
|
||||
- [Troubleshooting](./docs/troubleshooting.md)
|
||||
|
||||
## Stack
|
||||
|
||||
- **App** — Next.js 16 (App Router), React 19, TypeScript, Tailwind v4.
|
||||
- **Data** — Supabase (Postgres + Auth + RLS).
|
||||
- **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`](./CONTRIBUTING.md) and
|
||||
[`.github/SECURITY.md`](./.github/SECURITY.md).
|
||||
|
||||
## License
|
||||
|
||||
MIT — fork it, brand it, host it. Pull requests welcome.
|
||||
[MIT](./LICENSE). Fork it, brand it, host it.
|
||||
|
||||
@ -5,6 +5,8 @@ docs walk you from a freshly forked repo to a production deploy.
|
||||
|
||||
## Reading order
|
||||
|
||||
**Setup**
|
||||
|
||||
1. **[Getting started](./getting-started.md)** — fork the repo, install, run
|
||||
locally.
|
||||
2. **[Supabase setup](./supabase-setup.md)** — create the database, run the
|
||||
@ -12,11 +14,21 @@ docs walk you from a freshly forked repo to a production deploy.
|
||||
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.
|
||||
|
||||
**Deploy**
|
||||
|
||||
5. **[Deploy on Hostinger](./deployment-hostinger.md)** — recommended hosting
|
||||
walkthrough (Managed Node.js Hosting).
|
||||
6. **[Automations cron](./automations-and-cron.md)** — schedule the pending
|
||||
6. **[Alternative hosts](./deployment-alternatives.md)** — Vercel, Railway,
|
||||
raw VPS, Docker / Kubernetes.
|
||||
7. **[Automations cron](./automations-and-cron.md)** — schedule the pending
|
||||
executions drain so waits and delays fire.
|
||||
7. **[Troubleshooting](./troubleshooting.md)** — the usual suspects.
|
||||
|
||||
**Reference**
|
||||
|
||||
8. **[Architecture](./architecture.md)** — stack, folder layout, request
|
||||
lifecycle, where to change things.
|
||||
9. **[Troubleshooting](./troubleshooting.md)** — the usual suspects.
|
||||
|
||||
## What you will need before starting
|
||||
|
||||
@ -34,7 +46,8 @@ docs walk you from a freshly forked repo to a production deploy.
|
||||
- **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.
|
||||
- **Encryption** — AES-256-GCM for per-user WhatsApp access + verify
|
||||
tokens at rest. Legacy CBC-encrypted rows self-heal on next use.
|
||||
- **Scheduler** — cron (or any pinger) that hits `GET /api/automations/cron`.
|
||||
|
||||
## Getting help
|
||||
|
||||
160
docs/architecture.md
Normal file
160
docs/architecture.md
Normal file
@ -0,0 +1,160 @@
|
||||
# Architecture
|
||||
|
||||
One-page tour of the codebase — so you know where to look when you
|
||||
want to change something in your fork.
|
||||
|
||||
## Stack
|
||||
|
||||
| Layer | Tool | Why |
|
||||
|---|---|---|
|
||||
| Rendering | **Next.js 16** (App Router) | Server components for data-fetch pages; client components where interactivity's needed. React 19. |
|
||||
| UI | **Tailwind v4** + **shadcn/base-ui** primitives | Tailwind's zero-runtime styling, shadcn patterns for composable, dark-theme-first components. |
|
||||
| Data + Auth | **Supabase** | Postgres with Row-Level Security, built-in email/password auth, Storage for avatars, Realtime for the inbox. |
|
||||
| WhatsApp | **Meta Cloud API** | Official Business API. No third-party gateway. |
|
||||
| Encryption | `node:crypto` AES-256-GCM | Per-user WhatsApp access + verify tokens at rest. |
|
||||
| Scheduler | External HTTP pinger | Hits `GET /api/automations/cron` to drain Wait-step executions. |
|
||||
|
||||
No ORM, no GraphQL layer, no dedicated backend. The Next server-side
|
||||
routes read and write Supabase directly via `@supabase/ssr`.
|
||||
|
||||
## Folder layout
|
||||
|
||||
```
|
||||
wacrm/
|
||||
├─ src/
|
||||
│ ├─ app/ Next.js App Router routes
|
||||
│ │ ├─ (auth)/ login, signup, forgot-password
|
||||
│ │ ├─ (dashboard)/ authenticated UI
|
||||
│ │ │ ├─ dashboard/ home / metrics / activity feed
|
||||
│ │ │ ├─ inbox/ shared inbox
|
||||
│ │ │ ├─ contacts/ contacts + tags
|
||||
│ │ │ ├─ pipelines/ Kanban deals
|
||||
│ │ │ ├─ broadcasts/ campaign list + builder
|
||||
│ │ │ ├─ automations/ flow builder + logs
|
||||
│ │ │ └─ settings/ Profile / WhatsApp / Templates / Tags
|
||||
│ │ ├─ docs/ this documentation, rendered
|
||||
│ │ ├─ api/ JSON endpoints (server-only)
|
||||
│ │ │ ├─ whatsapp/webhook/ inbound from Meta
|
||||
│ │ │ ├─ whatsapp/send/ outbound message
|
||||
│ │ │ ├─ whatsapp/broadcast/ bulk dispatch
|
||||
│ │ │ ├─ whatsapp/config/ settings read/write
|
||||
│ │ │ ├─ whatsapp/templates/ template sync
|
||||
│ │ │ ├─ whatsapp/media/[id]/ media relay
|
||||
│ │ │ └─ automations/ engine + cron + CRUD
|
||||
│ │ ├─ page.tsx marketing landing
|
||||
│ │ ├─ layout.tsx root layout, metadata, icon
|
||||
│ │ ├─ opengraph-image.tsx dynamic OG image
|
||||
│ │ └─ icon.tsx dynamic favicon
|
||||
│ ├─ components/
|
||||
│ │ ├─ landing/ marketing page sections
|
||||
│ │ ├─ dashboard/ dashboard widgets
|
||||
│ │ ├─ inbox/ conversation list, thread, composer
|
||||
│ │ ├─ contacts/, pipelines/, broadcasts/, automations/, settings/
|
||||
│ │ ├─ docs/ docs viewer shell
|
||||
│ │ ├─ seo/ JSON-LD helpers
|
||||
│ │ ├─ layout/ header, sidebar, shell
|
||||
│ │ └─ ui/ shadcn/base-ui primitives
|
||||
│ ├─ hooks/ use-auth, use-realtime, etc.
|
||||
│ ├─ lib/
|
||||
│ │ ├─ supabase/ client, server, middleware factories
|
||||
│ │ ├─ whatsapp/ Meta API client, encryption, phone utils
|
||||
│ │ ├─ automations/ engine, steps, validation, templates
|
||||
│ │ ├─ dashboard/ queries + date utils
|
||||
│ │ ├─ docs/ markdown loader for /docs/
|
||||
│ │ ├─ seo/ site config, FAQ data, structured data
|
||||
│ │ └─ rate-limit.ts per-user token bucket
|
||||
│ ├─ types/ shared TypeScript types
|
||||
│ └─ middleware.ts session-refresh middleware
|
||||
├─ supabase/
|
||||
│ └─ migrations/ idempotent SQL files, run in order
|
||||
├─ docs/ you are here
|
||||
├─ public/ static assets
|
||||
└─ next.config.ts Cache-Control + security headers
|
||||
```
|
||||
|
||||
## Request lifecycle: inbound WhatsApp message
|
||||
|
||||
```
|
||||
Meta Cloud API ──POST──▶ /api/whatsapp/webhook
|
||||
│
|
||||
├─ verifyMetaWebhookSignature (HMAC-SHA256)
|
||||
│ └─ rejects 401 if META_APP_SECRET unset or wrong
|
||||
│
|
||||
├─ supabaseAdmin (service-role, lazy init)
|
||||
│
|
||||
├─ find contact by phone (create if new)
|
||||
├─ find or create conversation
|
||||
├─ insert message row
|
||||
│
|
||||
├─ fire runAutomationsForTrigger(...)
|
||||
│ └─ matches automations on new_message / keyword
|
||||
│
|
||||
└─ 200 OK (Meta retries otherwise)
|
||||
|
||||
Realtime fan-out:
|
||||
messages INSERT ──▶ supabase/realtime ──▶ inbox page subscription
|
||||
└─ appends to thread without refetch
|
||||
```
|
||||
|
||||
## Request lifecycle: outbound message from the inbox
|
||||
|
||||
```
|
||||
Composer ──fetch──▶ /api/whatsapp/send
|
||||
│
|
||||
├─ createClient() — user-scoped Supabase client
|
||||
├─ auth.getUser() — 401 if unauthed
|
||||
├─ checkRateLimit('send:<uid>', 60/min)
|
||||
│
|
||||
├─ select whatsapp_config row (RLS-scoped)
|
||||
├─ decrypt(access_token)
|
||||
│ └─ self-heal: upgrade CBC → GCM (fire-and-forget)
|
||||
│
|
||||
├─ sendTextMessage / sendTemplateMessage (Meta API)
|
||||
├─ retry with phone-number variants on "not allowed"
|
||||
│
|
||||
├─ insert message row with status = 'sent'
|
||||
└─ 200 + wamid
|
||||
|
||||
UI:
|
||||
Optimistic temp row shown immediately.
|
||||
Real row arrives via Supabase realtime → replaces temp.
|
||||
If 429 / 5xx: temp row flips to status = 'failed'.
|
||||
```
|
||||
|
||||
## Security primitives
|
||||
|
||||
- **Row-Level Security** on every table. Users see only their own
|
||||
rows via `auth.uid() = user_id`. Service-role bypasses RLS; only
|
||||
server-only modules use it.
|
||||
- **Encryption** (`src/lib/whatsapp/encryption.ts`) — AES-256-GCM for
|
||||
WhatsApp tokens at rest. Backward-compatible decrypt for legacy
|
||||
CBC rows; self-heals on first use.
|
||||
- **Webhook signatures** (`src/lib/whatsapp/webhook-signature.ts`) —
|
||||
HMAC-SHA256 with `META_APP_SECRET`. Fail-closed if the env var
|
||||
isn't set.
|
||||
- **Cron secret** — `GET /api/automations/cron` requires
|
||||
`x-cron-secret: <AUTOMATION_CRON_SECRET>`. Constant-ish string
|
||||
comparison.
|
||||
- **Rate limiting** (`src/lib/rate-limit.ts`) — per-user fixed window,
|
||||
process-local `Map`. Swap for Redis/Upstash at horizontal scale.
|
||||
- **HTTP headers** (`next.config.ts`) — HSTS, nosniff,
|
||||
X-Frame-Options: DENY, Referrer-Policy, Permissions-Policy, and a
|
||||
report-only CSP.
|
||||
|
||||
## Where to change things
|
||||
|
||||
| Want to change… | Start here |
|
||||
|---|---|
|
||||
| Marketing copy / landing page | `src/app/page.tsx` + `src/components/landing/*` |
|
||||
| Dashboard metrics | `src/lib/dashboard/queries.ts` + `src/components/dashboard/*` |
|
||||
| Inbox behaviour | `src/app/(dashboard)/inbox/page.tsx` + `src/components/inbox/*` |
|
||||
| Automation triggers / actions | `src/lib/automations/engine.ts`, `steps-tree.ts`, `meta-send.ts` |
|
||||
| Add a DB column | new migration in `supabase/migrations/NNN_*.sql`, then update the matching `src/types/*.ts` |
|
||||
| Change auth provider | `src/lib/supabase/{client,server}.ts` + `src/hooks/use-auth.tsx` + `middleware.ts` |
|
||||
| Add a new API route | `src/app/api/<name>/route.ts`, pattern after existing routes |
|
||||
| Tweak rate limits | `RATE_LIMITS` in `src/lib/rate-limit.ts` |
|
||||
|
||||
## Next step
|
||||
|
||||
- [Alternative hosts](./deployment-alternatives.md) — Vercel, Railway,
|
||||
raw VPS.
|
||||
145
docs/deployment-alternatives.md
Normal file
145
docs/deployment-alternatives.md
Normal file
@ -0,0 +1,145 @@
|
||||
# Alternative hosts
|
||||
|
||||
[Hostinger Managed Node.js Hosting](./deployment-hostinger.md) is the
|
||||
recommended default — zero-ops, Git deploy from hPanel, AutoSSL. But
|
||||
WaCRM is a plain Next.js app; any host that runs long-running
|
||||
Node.js 20+ will work. This page is a quick sketch for the common
|
||||
alternatives. Each block assumes you've already completed
|
||||
[Supabase setup](./supabase-setup.md) and [WhatsApp setup](./whatsapp-setup.md).
|
||||
|
||||
## Vercel
|
||||
|
||||
1. Push your fork to GitHub.
|
||||
2. <https://vercel.com/new> → **Import Git Repository** → pick the fork.
|
||||
3. **Environment Variables**: paste every value from
|
||||
[`environment-variables.md`](./environment-variables.md). Mark the
|
||||
`NEXT_PUBLIC_*` ones as available at build time (Vercel does this
|
||||
automatically).
|
||||
4. Deploy. Vercel handles HTTPS, preview URLs, and edge routing.
|
||||
5. Attach your domain (Vercel → Project → Settings → Domains).
|
||||
6. Update Meta → WhatsApp → Configuration → Webhook to
|
||||
`https://<your-domain>/api/whatsapp/webhook`.
|
||||
|
||||
**Automations cron**: Vercel has built-in cron (Pro plan). Add to
|
||||
[`vercel.json`](https://vercel.com/docs/cron-jobs):
|
||||
|
||||
```json
|
||||
{
|
||||
"crons": [
|
||||
{ "path": "/api/automations/cron", "schedule": "* * * * *" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Vercel cron hits the endpoint server-to-server but **doesn't let you
|
||||
send custom headers**. The simplest path is to skip `x-cron-secret`
|
||||
and gate on Vercel's `x-vercel-cron` header instead:
|
||||
|
||||
```ts
|
||||
// adjust src/app/api/automations/cron/route.ts
|
||||
if (request.headers.get('x-vercel-cron') !== '1' &&
|
||||
request.headers.get('x-cron-secret') !== process.env.AUTOMATION_CRON_SECRET) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
```
|
||||
|
||||
**Trade-offs**:
|
||||
|
||||
- ✅ Fastest onboarding, preview URLs per PR, global CDN.
|
||||
- ⚠️ Serverless functions have cold starts — inbound webhooks from
|
||||
Meta may occasionally take an extra second on the first hit.
|
||||
- ⚠️ The in-memory [rate limiter](./architecture.md#security-primitives)
|
||||
is per-function-instance, so effective limits multiply across
|
||||
regions. Swap for Upstash Redis if that matters.
|
||||
|
||||
## Railway
|
||||
|
||||
1. <https://railway.app/new> → **Deploy from GitHub repo** → pick your
|
||||
fork.
|
||||
2. Railway detects Next.js automatically. Default build +
|
||||
start commands are correct.
|
||||
3. **Variables**: add every value from
|
||||
[`environment-variables.md`](./environment-variables.md).
|
||||
4. **Generate Domain** under Settings, or attach a custom domain.
|
||||
5. Update Meta webhook URL, same as above.
|
||||
|
||||
**Automations cron**: Railway has built-in cron. Services → **+ Cron**:
|
||||
|
||||
- Schedule: `* * * * *`
|
||||
- Command:
|
||||
```
|
||||
curl -s -H "x-cron-secret: $AUTOMATION_CRON_SECRET" https://<your-domain>/api/automations/cron
|
||||
```
|
||||
|
||||
**Trade-offs**:
|
||||
|
||||
- ✅ Long-running processes (no cold starts), built-in Redis if you
|
||||
need one, usage-based pricing.
|
||||
- ⚠️ No preview deploys per PR out of the box (paid feature).
|
||||
|
||||
## Raw VPS (any provider)
|
||||
|
||||
Any Ubuntu 22/24 or Debian 12 VPS with 2 GB+ RAM works. The
|
||||
Hostinger VPS walkthrough in
|
||||
[`deployment-hostinger.md`](./deployment-hostinger.md) (at the bottom,
|
||||
"When to reach for a VPS instead") gives the exact commands — PM2 +
|
||||
nginx + certbot. Same commands apply on DigitalOcean, Hetzner, Linode,
|
||||
AWS Lightsail, OVH, etc. Only the billing dashboard changes.
|
||||
|
||||
Systemd cron is the obvious scheduler:
|
||||
|
||||
```cron
|
||||
* * * * * curl -s -H "x-cron-secret: $AUTOMATION_CRON_SECRET" https://<your-domain>/api/automations/cron > /dev/null
|
||||
```
|
||||
|
||||
**Trade-offs**:
|
||||
|
||||
- ✅ Most control (custom binaries, private networking, your own
|
||||
observability stack), cheapest at scale.
|
||||
- ⚠️ You are the ops team. Patching, TLS renewal, log rotation, backup
|
||||
to S3 — all you.
|
||||
|
||||
## Self-hosted Docker / Kubernetes
|
||||
|
||||
No official image is shipped. If you containerise, the app is a
|
||||
plain Next.js standalone build:
|
||||
|
||||
```Dockerfile
|
||||
FROM node:20-alpine AS deps
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
FROM node:20-alpine AS build
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
COPY --from=build /app/.next ./.next
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY --from=build /app/package.json ./
|
||||
COPY --from=build /app/public ./public
|
||||
EXPOSE 3000
|
||||
CMD ["npm", "start"]
|
||||
```
|
||||
|
||||
Pass env vars via `--env-file` or a Kubernetes Secret. The cron ping
|
||||
stays an external concern (K8s CronJob, a sidecar, or an external
|
||||
uptime monitor).
|
||||
|
||||
## Which should I pick?
|
||||
|
||||
| If you want… | Pick |
|
||||
|---|---|
|
||||
| Zero-ops, lowest-friction deploy | **Hostinger Managed Node.js** |
|
||||
| Preview URLs per PR, global edge | **Vercel** |
|
||||
| Long-running processes, simple cron | **Railway** |
|
||||
| Full control, cheapest at scale, you're OK on ops | **VPS / self-host** |
|
||||
| Air-gapped or multi-region with your own K8s | **Docker / Kubernetes** |
|
||||
|
||||
None of these are one-way doors — they all run the same fork of the
|
||||
same Next.js app.
|
||||
@ -44,14 +44,24 @@ const ORDER: Record<string, { order: number; section: string; description: strin
|
||||
section: 'Deploy',
|
||||
description: 'Ship WaCRM on Hostinger Managed Node.js Hosting.',
|
||||
},
|
||||
'automations-and-cron': {
|
||||
'deployment-alternatives': {
|
||||
order: 6,
|
||||
section: 'Deploy',
|
||||
description: 'Vercel, Railway, raw VPS, Docker — pick what fits.',
|
||||
},
|
||||
'automations-and-cron': {
|
||||
order: 7,
|
||||
section: 'Deploy',
|
||||
description: 'Schedule the drain so Wait steps resume on time.',
|
||||
},
|
||||
architecture: {
|
||||
order: 8,
|
||||
section: 'Reference',
|
||||
description: 'Stack, folder layout, request lifecycle.',
|
||||
},
|
||||
troubleshooting: {
|
||||
order: 7,
|
||||
section: 'Operate',
|
||||
order: 9,
|
||||
section: 'Reference',
|
||||
description: 'The usual suspects when something breaks.',
|
||||
},
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user