Prepare server deployment

This commit is contained in:
2026-05-12 16:21:00 +07:00
parent ac2cfca335
commit 713bfbcbb9
9 changed files with 120 additions and 16 deletions

View File

@ -25,3 +25,35 @@ cp .env.example .env
npm install
npm run dev
```
## Deploy test server
Target deploy:
- domain `wa.iptek.co`
- app port `127.0.0.1:3007`
- reverse proxy `nginx`
Contoh langkah di server:
```bash
cd /var/www
git clone https://git.iptek.co/wirabasalamah/webhook-test.git wa-test-nextjs
cd wa-test-nextjs
cp .env.example .env
npm ci
npm run build
npx pm2 start ecosystem.config.cjs
npx pm2 save
```
Set `.env` minimal:
```bash
NEXT_PUBLIC_APP_URL=https://wa.iptek.co
WHATSAPP_VERIFY_TOKEN=...
WHATSAPP_ACCESS_TOKEN=...
WHATSAPP_PHONE_NUMBER_ID=...
WA_TEST_NUMBER=...
WA_TEST_LOGIN_USERNAME=...
WA_TEST_LOGIN_PASSWORD=...
SESSION_SECRET=...
```
Contoh config nginx ada di `deploy/nginx/wa.iptek.co.conf`.

View File

@ -0,0 +1,19 @@
server {
listen 80;
listen [::]:80;
server_name wa.iptek.co;
client_max_body_size 10m;
location / {
proxy_pass http://127.0.0.1:3007;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 60s;
}
}

13
ecosystem.config.cjs Normal file
View File

@ -0,0 +1,13 @@
module.exports = {
apps: [
{
name: 'wa-test-nextjs',
script: 'npm',
args: 'run start:3007',
cwd: '/var/www/wa-test-nextjs',
env: {
NODE_ENV: 'production',
},
},
],
}

4
next-env.d.ts vendored
View File

@ -1,4 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
// This file is auto-generated by Next.js
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View File

@ -6,12 +6,13 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
"start:3007": "next start -p 3007 -H 127.0.0.1",
"lint": "eslint ."
},
"dependencies": {
"next": "16.0.0",
"react": "19.2.0",
"react-dom": "19.2.0"
"next": "16.2.6",
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"typescript": "^5",
@ -19,6 +20,6 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.0.0"
"eslint-config-next": "16.2.6"
}
}

View File

@ -8,7 +8,7 @@ export default async function TestPage({ searchParams }: { searchParams: Promise
redirect('/login')
}
const logs = readJsonFile<any[]>('webhook-logs.json', [])
const logs = readJsonFile<unknown[]>('webhook-logs.json', [])
const state = readJsonFile<Record<string, unknown>>('flow-state.json', {})
const params = await searchParams

View File

@ -8,7 +8,7 @@ export default async function WebhookLogsPage() {
redirect('/login')
}
const logs = readJsonFile<any[]>('webhook-logs.json', [])
const logs = readJsonFile<unknown[]>('webhook-logs.json', [])
return (
<div className="wrap">

View File

@ -1,6 +1,25 @@
import { appendLog, readJsonFile, writeJsonFile } from './storage'
type FlowState = Record<string, { step: string; name?: string }>
type WebhookValue = {
messages?: IncomingMessage[]
statuses?: unknown[]
}
type WebhookChange = {
value?: WebhookValue
}
type WebhookEntry = {
changes?: WebhookChange[]
}
type WebhookPayload = {
entry?: WebhookEntry[]
}
type IncomingMessage = {
from?: string
text?: {
body?: string
}
}
function normalizeNumber(number?: string | null) {
return (number || '').replace(/\D+/g, '')
@ -37,7 +56,7 @@ export async function sendTextMessage(to: string, message: string) {
return payload
}
export async function handleWebhook(payload: any) {
export async function handleWebhook(payload: WebhookPayload) {
appendLog({ type: 'webhook_received', payload, created_at: new Date().toISOString() })
for (const entry of payload.entry || []) {
@ -55,7 +74,7 @@ export async function handleWebhook(payload: any) {
}
}
async function handleIncomingMessage(message: any) {
async function handleIncomingMessage(message: IncomingMessage) {
const from = message.from || ''
appendLog({ type: 'incoming_message', from, message, created_at: new Date().toISOString() })

View File

@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": false,
"skipLibCheck": true,
"strict": true,
@ -11,13 +15,27 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"plugins": [{ "name": "next" }],
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
"@/*": [
"./src/*"
]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}