parseEnable()'s generic fallback (return true for an unset var) is correct
for the payment-method toggles it's shared with, but wrong for a security
gate: LOG_EXPOSE_API controlled whether /api/logs*, /openapi.json, and /docs
serve anything at all, and previously defaulted to true (open) when the env
var was absent, contradicting what .env.example already documented as the
safe default. Now explicitly defaults to 'false'.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
server/openapi.json, server/README.md, and the Postman collection used what
turned out to be real customer names/phone numbers and a real Midtrans
webhook notification (copied during earlier debugging) as documentation
examples instead of fabricated placeholder data. Replaced with clearly
synthetic values (Budi Santoso, DEMO-MERCHANT-*, placeholder UUIDs/signature).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Documents every environment variable read by server/index.cjs and the Vite
frontend (grep-verified against process.env.* / import.meta.env.* usage),
with placeholder values only — no real secrets. Not gitignored (.gitignore
already carves out an exception for it).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Reorganize into folders (Health & Config, Payment Links, Payment Operations,
Webhook, Logs & Docs, Dev/Test) and add every route that was missing:
GET/POST /api/config, POST /createtransaksi (ERP shape), Charge (Core API),
Create Snap Token, GET /api/logs, GET /api/logs/files, GET /api/logs/view,
GET /openapi.json, GET /docs, and the LOG_EXPOSE_API-only echo/echo2/
test-notify-erp endpoints. The Logs & Docs folder carries collection-level
Basic Auth (log_user/log_pass variables) shared by all its requests.
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>
v4-backup/ and web-bundles/ contain the BMad-Method agent-orchestration
framework (agent definitions, checklists, templates, game-dev/creative-writing
expansion packs) accidentally left in the repo. Nothing in server/ or src/
references either directory.
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.
- Add customerName prop to PaymentSheet component
- Display customer name in payment summary below Order ID
- Pass customer name from CheckoutPage form to PaymentSheet
- Fix TypeScript build errors (remove unused variables)
- Improve error logging in API interceptor
- Clean up snapLoader (remove unused snapLoading variable)
- Clean up PayPage (remove unused allowedMethods, runtimeCfg)
- Move lockOrder call to onSuccess callback in PayPage
- Add BOM handling in test-create-payment-link script
- Update test payment data (REFNO-002, TKG-2512041)
- Add guard in AutoSnapPayment to only trigger when orderId and amount are valid
- Show loading state while waiting for payment data to resolve
- Prevent premature Snap token creation with empty/invalid data
- Fix PayPage and CheckoutPage auto-payment flow
- Add AutoSnapPayment component that auto-triggers Snap popup on mount
- Update CheckoutPage: auto-open Snap payment after form submission
- Update PayPage: auto-open Snap payment on page load
- Remove manual button clicks for smoother UX
- Add loading states and error handling for auto-payment flow
- Created src/lib/errorMessages.ts for user-friendly Bahasa Indonesia error messages
- Created src/components/LoadingOverlay.tsx with Framer Motion animations
- Updated BankTransferPanel with LoadingOverlay and mapErrorToUserMessage
- All 4 error catch blocks now use user-friendly messages
- GoPayPanel imports restored (ready for next iteration)
Story: 1.1 - Prevent Duplicate VA/QR/Code Generation & Improve Feedback
Status: Partial (BankTransferPanel complete, GoPayPanel & CStorePanel pending)