diff --git a/README.md b/README.md index b94d458..b1d9969 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,72 @@ -# Core Midtrans CIFO (Frontend) +# Midtrans Middleware (CIFO) -Frontend Vite + React untuk integrasi Midtrans Core API dengan UI kustom. +Vite + React frontend dan Express backend untuk integrasi pembayaran Midtrans (Core API + Snap) dengan sistem ERP. + +## Struktur Project + +``` +server/ Express backend (single-file: server/index.cjs) +src/ Frontend React (checkout, halaman /pay, dashboard demo) +postman/ Postman collection — seluruh endpoint API +tests/ Script testing manual untuk backend +scripts/ Utility script (mis. fetch-logos.mjs) +``` ## Setup 1) Duplikasi file contoh env dan isi nilainya: ```bash -cp .env.example .env.local +cp .env.example .env ``` -Isi `.env.local` (lihat `.env.example` untuk referensi): +Isi `.env` sesuai kebutuhan — lihat `.env.example` untuk daftar lengkap variabel beserta penjelasannya (Midtrans key, `EXTERNAL_API_KEY`, `PAYMENT_LINK_SECRET`, `LOG_BASIC_AUTH_USER/PASS`, dll). Generate secret yang kuat dengan: -``` -VITE_API_BASE_URL=http://localhost:8000/api -VITE_MIDTRANS_CLIENT_KEY=YOUR_CLIENT_KEY -VITE_MIDTRANS_ENV=sandbox +```bash +node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))" ``` -2) Jalankan pengembangan: +2) Install dependencies: ```bash npm install -npm run dev ``` -App akan tersedia di `http://localhost:5173/` (atau port lain jika 5173 dipakai). +3) Jalankan backend dan frontend (dua terminal terpisah): + +```bash +npm run server # backend Express, default http://localhost:8000 +npm run dev # frontend Vite, default http://localhost:5173 +``` + +## API Backend + +Dokumentasi lengkap seluruh endpoint ada di dua tempat: + +- **Interaktif (Scalar)** — buka `http://localhost:8000/docs` di browser (dilindungi HTTP Basic Auth, kredensial sama dengan `/api/logs*`, lihat `LOG_BASIC_AUTH_USER`/`LOG_BASIC_AUTH_PASS`). Spec mentah tersedia di `/openapi.json`. +- **Postman** — import `postman/Midtrans-Middleware.postman_collection.json`, sudah berisi seluruh route (payment link, charge, snap token, webhook, logs, dev/test endpoints) dikelompokkan per folder. + +Detail arsitektur & alur pembayaran ada di [`server/README.md`](server/README.md). + +## Alat Bantu Operasional + +- **Log viewer** — `http://localhost:8000/api/logs/view` (dilindungi Basic Auth). Bisa filter per level, cari teks/order_id, dan klik nilai apa pun untuk trace lintas baris log yang berkaitan. Log otomatis dihapus setelah `LOG_RETENTION_DAYS` (default 30 hari). +- **Payment link** dibuat lewat `POST /api/payment-links` (payload langsung `order_id`/`nominal`/`customer`/`expire_at`) atau `POST /createtransaksi` (payload ERP `mercant_id`/`item[]`). ## Catatan Integrasi Midtrans -- Client Key hanya digunakan di frontend (mis. tokenisasi kartu/3DS). Server Key TIDAK pernah di frontend. -- Semua request ke Midtrans dilakukan lewat backend (`VITE_API_BASE_URL`). Frontend memanggil endpoint seperti `/payments/:orderId/status`. -- Status real-time dapat diimplementasikan via polling (TanStack Query) atau SSE/WebSocket dari backend. +- Client Key hanya digunakan di frontend (mis. tokenisasi kartu/3DS, Snap.js). Server Key **tidak pernah** dikirim ke frontend. +- Order pembayaran punya dua alur: (1) link yang dibagikan ke pelanggan (dibuat lewat `/createtransaksi` atau `/api/payment-links`, di-resolve oleh halaman `/pay/:token`), dan (2) checkout langsung dari browser (`/api/payments/charge`, `/api/payments/snap/token`) tanpa pra-registrasi — keduanya diberi rate limit untuk mencegah abuse. +- `order_id` yang mengandung karakter selain alfanumerik/`- _ ~ .` (mis. `:`) otomatis disanitasi jadi `.` sebelum dikirim ke Midtrans. +- Status real-time dapat diimplementasikan via polling (TanStack Query) atau webhook (`POST /api/payments/notification`) yang meneruskan notifikasi ke ERP. -## Struktur Env di Kode +## Struktur Env di Kode Frontend -- Akses env melalui modul `src/lib/env.ts`: - - `Env.API_BASE_URL` - - `Env.MIDTRANS_CLIENT_KEY` - - `Env.MIDTRANS_ENV` +Akses env melalui modul `src/lib/env.ts`: +- `Env.API_BASE_URL` +- `Env.MIDTRANS_CLIENT_KEY` +- `Env.MIDTRANS_ENV` ## Lisensi -Internal project skeleton. +Internal project — CIFO Group. diff --git a/server/README.md b/server/README.md index 286d50a..ebb5f20 100644 --- a/server/README.md +++ b/server/README.md @@ -2,7 +2,9 @@ Backend Express.js server untuk integrasi pembayaran Midtrans dengan sistem ERP. -## 📋 Daftar Isi +> Dokumentasi endpoint yang selalu sinkron dengan kode: buka `/docs` (Scalar, HTTP Basic Auth) atau `/openapi.json`. Untuk testing manual, import `postman/Midtrans-Middleware.postman_collection.json` — mencakup seluruh route di bawah ini. + +## Daftar Isi - [Fitur Utama](#fitur-utama) - [Konfigurasi Environment](#konfigurasi-environment) @@ -10,17 +12,18 @@ Backend Express.js server untuk integrasi pembayaran Midtrans dengan sistem ERP. - [Payment Flow](#payment-flow) - [Testing](#testing) - [Logging](#logging) +- [Keamanan](#keamanan) -## 🚀 Fitur Utama +## Fitur Utama ### 1. **Dual Mode Payment** - **CORE API**: Bank Transfer, Credit Card, GoPay/QRIS, Convenience Store - **SNAP**: Hosted payment interface dengan UI Midtrans ### 2. **Payment Link Generation** -- Generate secure payment link dengan signature validation -- Configurable TTL (Time To Live) -- Token-based authentication +- Dua bentuk payload: langsung (`order_id`/`nominal`/`customer`/`expire_at`) atau ERP (`mercant_id`/`item[]`) +- Signature HMAC-SHA256 pada token, TTL configurable +- `order_id` yang mengandung karakter selain `A-Za-z0-9-_~.` (mis. `:`) otomatis disanitasi jadi `.` sebelum dikirim ke Midtrans ### 3. **ERP Integration** - Notifikasi otomatis ke sistem ERP setelah pembayaran sukses @@ -32,207 +35,115 @@ Backend Express.js server untuk integrasi pembayaran Midtrans dengan sistem ERP. - Signature verification - Idempotent notification handling -### 5. **Advanced Logging** -- Level-based logging (debug, info, warn, error) -- In-memory log buffer -- Payload masking untuk sensitive data -- Jakarta timezone (WIB/UTC+7) +### 5. **State Persisten** +- `activeOrders`, `notifiedOrders`, `orderRetryCount`, `orderMerchantId` disimpan ke `server/data/state.json` (auto-save), jadi tidak hilang saat server restart -## ⚙️ Konfigurasi Environment +### 6. **Advanced Logging** +- Level-based logging (debug, info, warn, error), file harian (`LOGS_DDMMYYYY.log`) +- Auto-delete log lebih tua dari `LOG_RETENTION_DAYS` +- Log viewer interaktif di `/api/logs/view` (search, filter level, click-to-trace) +- Payload masking untuk sensitive data, Jakarta timezone (WIB/UTC+7) + +## Konfigurasi Environment + +Referensi lengkap ada di `.env.example` di root project. Ringkasan per kategori: ### Midtrans Configuration ```env -# Required MIDTRANS_SERVER_KEY=your-server-key MIDTRANS_CLIENT_KEY=your-client-key MIDTRANS_IS_PRODUCTION=false -# Payment Method Toggles ENABLE_BANK_TRANSFER=true ENABLE_CREDIT_CARD=true ENABLE_GOPAY=true ENABLE_CSTORE=true ``` -### Payment Link Configuration +### Payment Link & External API ```env -# External API Access -EXTERNAL_API_KEY=your-api-key - -# Payment Link Settings -PAYMENT_LINK_SECRET=your-secret-for-signing +EXTERNAL_API_KEY=your-api-key # X-API-KEY untuk /createtransaksi & POST /api/payment-links +PAYMENT_LINK_SECRET=your-signing-secret # HMAC secret untuk token link PAYMENT_LINK_TTL_MINUTES=1440 PAYMENT_LINK_BASE=http://localhost:5174/pay ``` ### ERP Integration ```env -# Single URL (legacy) ERP_NOTIFICATION_URL=https://your-erp.com/api/payment-notification -ERP_CLIENT_SECRET=your-erp-client-secret - -# Multi-URL (recommended) -ERP_NOTIFICATION_URLS=https://erp1.com/api/notif,https://erp2.com/api/notif - -# Toggle +ERP_NOTIFICATION_URLS=https://erp1.com/api/notif,https://erp2.com/api/notif # multi-URL, opsional +ERP_CLIENT_ID=your-erp-client-id # juga dipakai sebagai secret HMAC (fallback ERP_CLIENT_SECRET) ERP_ENABLE_NOTIF=true ``` -### Logging Configuration +### Logging & Admin Access ```env -# Logging Level: debug, info, warn, error LOG_LEVEL=info - -# Expose /api/logs endpoint (dev only) -LOG_EXPOSE_API=true - -# In-memory buffer size +LOG_EXPOSE_API=false # WARNING: default true kalau tidak di-set +LOG_BASIC_AUTH_USER= # wajib diisi di production untuk lindungi /api/logs* dan /docs +LOG_BASIC_AUTH_PASS= +LOG_RETENTION_DAYS=30 LOG_BUFFER_SIZE=1000 ``` -### Server Configuration +### CORS & Rate Limiting ```env -PORT=8000 -NODE_ENV=development +CORS_ALLOWED_ORIGINS=https://your-frontend.example.com # kosong = izinkan semua origin (dev default) +RATE_LIMIT_WINDOW_MS=60000 +RATE_LIMIT_MAX=20 ``` -## 📡 API Endpoints +### Server +```env +PORT=8000 +NODE_ENV=production # HARUS "production" di server production — banyak gerbang keamanan bergantung pada ini +``` + +## API Endpoints ### Health & Config #### `GET /api/health` Health check endpoint. -**Response:** -```json -{ - "ok": true, - "env": { - "isProduction": false, - "hasServerKey": true, - "hasClientKey": true - } -} -``` - #### `GET /api/config` -Get current payment configuration. +Ambil payment toggles & Midtrans client key saat ini. -**Response:** -```json -{ - "paymentToggles": { - "bank_transfer": true, - "credit_card": true, - "gopay": true, - "cstore": true - }, - "midtransEnv": "sandbox", - "clientKey": "SB-Mid-client-xxx" -} -``` - -#### `POST /api/config` (Dev Only) -Update payment toggles at runtime. - -**Request:** -```json -{ - "paymentToggles": { - "bank_transfer": false - } -} -``` +#### `POST /api/config` (non-production only) +Update payment toggles saat runtime. Return 403 kalau `NODE_ENV=production`. ### Payment Operations #### `POST /api/payments/charge` -Create payment transaction via Midtrans Core API. - -**Headers:** -``` -Content-Type: application/json -``` - -**Request Body:** -```json -{ - "payment_type": "bank_transfer", - "transaction_details": { - "order_id": "order-123", - "gross_amount": 150000 - }, - "bank_transfer": { - "bank": "bca" - } -} -``` - -**Response:** -```json -{ - "status_code": "201", - "status_message": "Success", - "transaction_id": "xxx", - "order_id": "order-123", - "va_numbers": [ - { - "bank": "bca", - "va_number": "12345678901" - } - ] -} -``` +Buat transaksi Core API (bank transfer, card, GoPay/QRIS, cstore). Dipanggil langsung dari browser checkout, tanpa perlu pra-registrasi order. **Rate-limited.** #### `POST /api/payments/snap/token` -Generate Snap token for hosted payment. - -**Request:** -```json -{ - "transaction_details": { - "order_id": "order-123", - "gross_amount": 150000 - }, - "customer_details": { - "first_name": "John", - "email": "john@example.com" - } -} -``` - -**Response:** -```json -{ - "token": "snap-token-xxx" -} -``` +Generate Snap token untuk hosted payment popup. Dipanggil langsung dari browser (`PayPage`/`CheckoutPage`). **Rate-limited.** #### `GET /api/payments/:orderId/status` -Check payment status. - -**Response:** -```json -{ - "status_code": "200", - "transaction_status": "settlement", - "order_id": "order-123", - "gross_amount": "150000.00" -} -``` +Cek status transaksi (passthrough Midtrans). Juga memicu fallback notifikasi ERP kalau status sudah sukses tapi belum ter-notify. ### Payment Link -#### `POST /createtransaksi` -Generate payment link (external ERP endpoint). - -**Headers:** +#### `POST /api/payment-links` — payload langsung +Requires `X-API-KEY`. **Rate-limited.** +```json +{ + "order_id": "ERPSKRIP-2608030000000627:TKG-260803000063", + "nominal": 179000, + "customer": { "name": "Yusnika Nur Faidah", "phone": "0881022144656", "email": "yusnika_nur_faidah@example.com" }, + "expire_at": 1785852063058 +} ``` -X-API-KEY: your-external-api-key -Content-Type: application/json +`order_id` dipakai apa adanya untuk tracking internal; versi yang dikirim ke Midtrans disanitasi (`:` dan karakter lain → `.`). `expire_at` dipakai kalau valid & di masa depan, kalau tidak fallback ke `PAYMENT_LINK_TTL_MINUTES`. + +**Response:** +```json +{ "status": "200", "messages": "SUCCESS", "data": { "url": "...", "order_id": "...", "midtrans_order_id": "...", "expire_at": 1785852063058 } } ``` -**Request:** +#### `POST /createtransaksi` — payload ERP (mercant_id/item) +Requires `X-API-KEY`. **Rate-limited.** ```json { "mercant_id": "merchant-001", @@ -240,134 +151,61 @@ Content-Type: application/json "nama": "John Doe", "email": "john@example.com", "no_telepon": "081234567890", - "item": [ - { - "item_id": "product-123", - "nama": "Product Name", - "harga": 150000, - "qty": 1 - } - ], + "item": [{ "item_id": "product-123", "nama": "Product Name", "harga": 150000, "qty": 1 }], "allowed_methods": ["bank_transfer", "gopay"] } ``` +`order_id` diturunkan sebagai `mercant_id.item[0].item_id` (dot-joined). `expire_at` TIDAK bisa di-supply client — dihitung server dari `PAYMENT_LINK_TTL_MINUTES`. **Response:** ```json -{ - "status": "200", - "messages": "SUCCESS", - "data": { - "url": "http://localhost:5174/pay/eyJ2Ijox..." - } -} +{ "status": "200", "messages": "SUCCESS", "data": { "url": "http://localhost:5174/pay/eyJ2Ijox..." } } ``` #### `GET /api/payment-links/:token` -Resolve payment link token. - -**Response:** -```json -{ - "order_id": "merchant-001:product-123", - "nominal": 150000, - "customer": { - "name": "John Doe", - "email": "john@example.com", - "phone": "081234567890" - }, - "expire_at": 1733280000000, - "allowed_methods": ["bank_transfer", "gopay"] -} -``` +Resolve token jadi detail order: `{ order_id, nominal, customer, expire_at, allowed_methods }`. ### Webhook #### `POST /api/payments/notification` -Midtrans webhook handler (unified for CORE & SNAP). +Handler webhook Midtrans (unified CORE & SNAP). Verifikasi `signature_key` (`SHA512(order_id+status_code+gross_amount+MIDTRANS_SERVER_KEY)`), lalu meneruskan notifikasi ke ERP. Return non-2xx kalau notifikasi ERP gagal supaya Midtrans retry. -**Request (from Midtrans):** -```json -{ - "order_id": "order-123", - "transaction_status": "settlement", - "gross_amount": "150000.00", - "signature_key": "xxx" -} -``` +### Logs & Docs (internal — HTTP Basic Auth di production) -**Response:** -```json -{ - "ok": true -} -``` +| Endpoint | Keterangan | +|---|---| +| `GET /api/logs` | Log in-memory terbaru (`?limit`, `?level`, `?q`) | +| `GET /api/logs/files` | Daftar file log harian | +| `GET /api/logs/files/:filename` | Isi satu file log (JSON), auto-redirect ke viewer HTML kalau diakses dari browser | +| `GET /api/logs/view?file=...` | Viewer interaktif: filter level, cari teks, klik nilai apa pun untuk trace | +| `GET /openapi.json` | Spec OpenAPI mentah | +| `GET /docs` | Dokumentasi API interaktif (Scalar) | -### Logging (Dev Only) +### Dev/Test (aktif hanya kalau `LOG_EXPOSE_API=true`) -#### `GET /api/logs?limit=100&level=info&q=payment` -Get recent logs. +- `POST /api/echo`, `POST /api/echo2` — mock endpoint untuk testing callback ERP +- `POST /api/test/notify-erp` — trigger `notifyERP()` langsung, bypass webhook -**Query Parameters:** -- `limit`: Max entries (1-1000, default: 100) -- `level`: Filter by level (debug|info|warn|error) -- `q`: Search keyword - -**Response:** -```json -{ - "count": 50, - "items": [ - { - "ts": "2024-12-04T12:00:00.000+07:00", - "level": "info", - "msg": "charge.request", - "meta": { - "id": "abc123", - "payment_type": "bank_transfer" - } - } - ] -} -``` - -### Testing (Dev Only) - -#### `POST /api/echo` -Echo endpoint untuk testing ERP notification. - -#### `POST /api/test/notify-erp` -Manual trigger ERP notification. - -**Request:** -```json -{ - "orderId": "order-123", - "nominal": "150000", - "mercant_id": "merchant-001" -} -``` - -## 🔄 Payment Flow +## Payment Flow ### 1. Payment Link Creation Flow ``` -ERP System → POST /createtransaksi → Server generates token → Payment URL +ERP System → POST /createtransaksi atau POST /api/payment-links → Server generate token → Payment URL ``` ### 2. Payment Execution Flow ``` -Customer → Payment URL → Frontend resolves token → -Choose method → POST /api/payments/charge or SNAP → Midtrans +Customer → Payment URL → Frontend resolve token → +Pilih metode → POST /api/payments/charge atau /api/payments/snap/token → Midtrans ``` ### 3. Payment Completion Flow ``` -Midtrans → Webhook → Verify signature → Update ledger → -Notify ERP → Mark order complete +Midtrans → Webhook → Verifikasi signature → Update ledger → +Notify ERP → Tandai order selesai ``` -### 4. ERP Notification Format +### 4. Format Notifikasi ke ERP ```json { "mercant_id": "merchant-001", @@ -376,115 +214,85 @@ Notify ERP → Mark order complete "signature": "sha512-hash" } ``` +**Perhitungan Signature:** `SHA512(mercant_id + status_code + nominal + ERP_CLIENT_ID)` -**Signature Calculation:** -``` -SHA512(mercant_id + status_code + nominal + ERP_CLIENT_SECRET) -``` +> Catatan: payload ke ERP **tidak** membawa `order_id` — pencocokan transaksi murni lewat `mercant_id`. Kalau satu `mercant_id` bisa punya lebih dari satu order aktif bersamaan, ERP perlu strategi lain untuk membedakannya. -## 🧪 Testing +## Testing Lihat folder `tests/` untuk file-file testing: ```bash -# Test create payment link node tests/test-create-payment-link.cjs - -# Test frontend payload node tests/test-frontend-payload.cjs - -# Test snap token node tests/test-snap-token.cjs ``` -Lihat `tests/README.md` untuk detail lengkap. +Atau pakai `postman/Midtrans-Middleware.postman_collection.json` — mencakup seluruh endpoint di atas, dikelompokkan per folder, termasuk request untuk mensimulasikan webhook Midtrans dari payload asli. -## 📝 Logging +## Logging ### Log Levels -- **debug**: Detailed information, typically of interest only when diagnosing problems -- **info**: General informational messages -- **warn**: Warning messages for potentially harmful situations -- **error**: Error events that might still allow the application to continue running +- **debug**: Detail untuk diagnosa masalah +- **info**: Informasi umum +- **warn**: Peringatan +- **error**: Error yang masih memungkinkan aplikasi jalan -### Log Format +### Format Log (file, satu baris per event) ``` -[2024-12-04T12:00:00.000+07:00] [info] charge.request {"id": "abc123", "payment_type": "bank_transfer"} +[2026-08-03T21:35:54.746+07:00] [INFO ] webhook.notifying_erp | {"order_id":"ERPSKRIP-2608030000000637.TKG-260801001361","mercant_id":"ERPSKRIP-2608030000000637"} ``` -### Important Log Events +Paling nyaman dibaca lewat `GET /api/logs/view` (filter level, cari teks, klik nilai untuk trace) daripada membaca file mentah. -#### Payment Lifecycle -- `charge.request`: Payment charge initiated -- `charge.success`: Charge successful -- `charge.error`: Charge failed -- `status.request`: Status check requested -- `webhook.received`: Webhook notification received +### Event Penting -#### ERP Integration -- `erp.notify.start`: ERP notification started -- `erp.notify.success`: ERP notified successfully -- `erp.notify.error`: ERP notification failed -- `erp.notify.skip`: Notification skipped (already sent or disabled) +**Payment Lifecycle:** `charge.request`, `charge.success`, `charge.error`, `status.request`, `webhook.received` -#### Security -- `webhook.signature.invalid`: Invalid webhook signature -- `createtransaksi.unauthorized`: Unauthorized API key +**Payment Link:** `payment-links.create.issued`, `createtransaksi.issued`, `paymentlink.resolve.success` -## 🔒 Security Features +**ERP Integration:** `erp.notify.start`, `erp.notify.success`, `erp.notify.error`, `erp.notify.skip` -1. **Signature Verification** - - Webhook signature validation - - Payment link token signing - - ERP notification signing +**Security:** `webhook.signature.invalid`, `createtransaksi.unauthorized`, `payment-links.create.unauthorized`, `admin.auth.failed`, `rate_limit.blocked` -2. **Idempotency** - - Prevent duplicate order creation - - Prevent duplicate ERP notifications - - Block re-charge for pending orders +## Keamanan -3. **API Key Authentication** - - External API key for `/createtransaksi` - - Dev mode fallback for easier local testing +1. **Signature Verification** — webhook, token payment link, notifikasi ERP semuanya ditandatangani/diverifikasi. +2. **Idempotency** — cegah duplikasi order/notifikasi ERP; state disimpan konsisten pakai `order_id` yang sudah disanitasi (Midtrans-safe) di semua map internal (`activeOrders`, `notifiedOrders`, `orderRetryCount`, `orderMerchantId`), sehingga tidak ada mismatch walau `order_id` asli mengandung karakter seperti `:`. +3. **API Key Authentication** — `X-API-KEY` untuk `/createtransaksi` dan `POST /api/payment-links`. Dev mode fallback (bypass) hanya aktif kalau `NODE_ENV !== 'production'` **dan** key belum di-set. +4. **HTTP Basic Auth untuk admin tooling** — `/api/logs*`, `/openapi.json`, `/docs` dilindungi `LOG_BASIC_AUTH_USER`/`PASS`. **Wajib di-set di production** — endpoint ini terbuka penuh secara default (`LOG_EXPOSE_API` default `true`) kalau tidak dikonfigurasi. +5. **Rate Limiting** — `/createtransaksi`, `/api/payment-links`, `/api/payments/charge`, `/api/payments/snap/token` dibatasi per-IP (`RATE_LIMIT_MAX` request per `RATE_LIMIT_WINDOW_MS`) untuk mencegah bot abuse / card-testing pada endpoint yang memang harus tetap bisa diakses langsung dari browser tanpa API key. +6. **CORS** — dibatasi lewat `CORS_ALLOWED_ORIGINS` (comma-separated). Kosong = izinkan semua origin (default dev). +7. **Payload Masking** — field sensitif (card number, CVV, token, server key) otomatis disamarkan di log. +8. **`NODE_ENV` production** — banyak gerbang keamanan (API key, Basic Auth) bergantung pada `isDevEnv()`. Pastikan proses production (`ecosystem.config.cjs`) benar-benar set `NODE_ENV=production`, lalu `pm2 restart --update-env` setelah mengubahnya. -4. **Payload Masking** - - Sensitive fields masked in logs - - Card numbers, CVV, tokens automatically hidden - -## 🚀 Running the Server +## Running the Server ```bash -# Install dependencies npm install - -# Start server -node server/index.cjs - -# Server runs on http://localhost:8000 +npm run server # atau: node server/index.cjs +# Server jalan di http://localhost:8000 ``` -## 📚 Related Documentation +## Common Issues -- [Tests README](../tests/README.md) - Testing documentation -- [Temp Files README](../temp/README.md) - Temporary files info -- [Frontend README](../README.md) - Main project README +### "Transaction already pending" +**Penyebab**: Order ID sudah punya transaksi pending di Midtrans. +**Solusi**: Pakai instruksi pembayaran yang ada, atau buat order baru dengan ID berbeda. -## 🐛 Common Issues +### "ERP notification failed" +**Penyebab**: Endpoint ERP tidak bisa diakses, atau signature mismatch (`ERP_CLIENT_ID` beda dengan yang dipakai ERP). +**Solusi**: Cek `ERP_NOTIFICATION_URL(S)` dan `ERP_CLIENT_ID`, replay payload webhook asli lewat request "Simulate Midtrans Notification (Local)" di Postman collection untuk debug. -### Issue: "Transaction already pending" -**Cause**: Order ID already has pending transaction in Midtrans -**Solution**: Use existing payment instructions or create new order with different ID +### "Invalid signature on webhook" +**Penyebab**: `MIDTRANS_SERVER_KEY` salah, atau webhook dari sumber tak sah. +**Solusi**: Pastikan `MIDTRANS_SERVER_KEY` sama dengan akun Midtrans yang memproses transaksi tersebut (sandbox vs production beda key). -### Issue: "ERP notification failed" -**Cause**: ERP endpoint unreachable or signature mismatch -**Solution**: Check `ERP_NOTIFICATION_URLS` and `ERP_CLIENT_SECRET` configuration +### Log/`/docs` mengembalikan 401 atau 503 +**Penyebab**: `LOG_BASIC_AUTH_USER`/`PASS` belum di-set di production (`NODE_ENV=production`). +**Solusi**: Set kedua env var tersebut, restart server. -### Issue: "Invalid signature on webhook" -**Cause**: Incorrect server key or webhook from unauthorized source -**Solution**: Verify `MIDTRANS_SERVER_KEY` matches your Midtrans account +## Support -## 📞 Support - -Untuk bantuan lebih lanjut, hubungi tim development atau lihat dokumentasi Midtrans: - [Midtrans API Documentation](https://docs.midtrans.com/) - [Midtrans Node.js Library](https://github.com/Midtrans/midtrans-nodejs-client)