Root README.md was frontend-only and didn't mention the backend at all.
server/README.md was stale relative to the endpoint/security changes in this
branch (missing POST /api/payment-links, the sanitized order_id behavior,
rate limiting, CORS, log retention, state persistence, admin auth) and linked
to a temp/README.md that no longer exists. Both now point to /docs, /openapi.json,
and the Postman collection as the source of truth for the API surface.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- server/logviewer.html: readable log viewer at GET /api/logs/view — level
filter chips, free-text search, and click-to-trace (clicking any field value
re-filters to every line sharing it, e.g. an order_id or request id across
its whole lifecycle). GET /api/logs/files/:filename now redirects browser
navigation here instead of returning raw JSON (Accept: application/json
still gets the JSON body).
- server/openapi.json + server/api-docs.html: OpenAPI 3.0 spec and a Scalar
reference page served at GET /openapi.json and GET /docs. Scalar is loaded
from a version-pinned CDN URL with a Subresource Integrity hash rather than
installed as a dependency.
- Generalize requireLogBasicAuth -> requireAdminAuth since the same HTTP Basic
Auth credentials now gate /api/logs*, /openapi.json, and /docs alike.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- ecosystem.config.cjs: NODE_ENV was hardcoded to "development" even for the
production pm2 process, silently disabling every isDevEnv()-gated security
check (API key bypass, admin auth bypass) in production. Now "production".
- Restrict CORS via configurable CORS_ALLOWED_ORIGINS (falls back to allow-all
with a warning when unset, so this doesn't break existing traffic on deploy).
- Add an in-process, dependency-free rate limiter on /createtransaksi,
/api/payment-links, /api/payments/charge, and /api/payments/snap/token to
curb bot abuse / card-testing on endpoints the browser checkout must be able
to call directly (an API-key gate would break that legitimate flow).
- Auto-delete LOGS_*.log files older than LOG_RETENTION_DAYS (default 30).
- Persist activeOrders, notifiedOrders, orderRetryCount, and orderMerchantId to
server/data/state.json via Proxy-wrapped Map/Set (schedulePersist on every
mutation), so idempotency and retry-suffix tracking survive restarts/crashes
instead of resetting to empty every deploy.
- Remove processPaymentCompletion, dead code with no call sites.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
State maps (activeOrders, notifiedOrders, orderRetryCount, orderMerchantId)
were keyed by the raw order_id in /createtransaksi and /api/payment-links,
but Midtrans webhooks and status checks always report back the sanitized
('.'-joined) order_id. Whenever the original order_id contained characters
Midtrans disallows (e.g. ':'), the two never matched — breaking duplicate/
already-completed detection and retry-suffix lookups. Both endpoints now
key exclusively on the sanitized order_id, with retry-suffix support added
to /api/payment-links for parity with /createtransaksi.
Also add HTTP Basic Auth (requireLogBasicAuth) in front of /api/logs,
/api/logs/files, and /api/logs/files/:filename — these were previously
gated only by LOG_EXPOSE_API, which defaults to true, leaving order data
and transaction details publicly readable with no credentials.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a new endpoint that creates a shareable Midtrans Snap payment link
straight from { order_id, nominal, customer, expire_at } without remapping
to the mercant_id/item[] shape required by /createtransaksi.
order_id is sanitized (':' and other disallowed chars -> '.') before being
sent to Midtrans, while the mercant_id used for ERP webhook notification is
derived from the original, unsanitized order_id so ERP always gets a clean
identifier instead of the full composite order_id.
Includes a Postman collection covering link creation, resolution, status
check, and replaying a captured Midtrans notification payload for local
webhook debugging.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Midtrans rejects order_id values containing ':' (only alphanumeric and
- _ ~ . are allowed). The composite mercant_id:item_id order_id and the
:rN retry suffix violated this, causing Snap token requests to fail
with a 400 once both a mercant_id and item_id were present.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Added 'Inter' font to global CSS and Tailwind config for improved typography.
- Deleted unused test files related to payment link creation and Snap token testing.
- Created comprehensive README for server setup, API endpoints, and payment flow.
- Added testing documentation for easier integration and usage of the payment system.
Update default payment link TTL from 30 minutes to 24 hours across frontend and backend. Also modify countdown display to show hours in addition to minutes and seconds.
otifyERP to broadcast payload to all endpoints and aggregate results\n- Log per-endpoint result and summary via erp.notify.success and erp.notify.summary\n- Add dev endpoint /api/echo2 for local multi-URL testing\n\nThis ensures signature is included in body for all endpoints and improves visibility in logs.
GoPay: spinner QRIS dalam frame, hilangkan QR dummy saat menunggu, hapus tombol Buat QR, sanitasi URL actions. CStore: panel pilihan toko di Step 2, auto-generate kode dengan guard StrictMode, perbaiki busy agar tidak nyangkut setelah respons 201. Checkout: jangan auto-advance untuk CStore, oper defaultStore sesuai pilihan. BankTransfer: stabilisasi in-flight promise untuk VA (sebelumnya).