- 31 Aug, 2026 11 commits
-
-
createTransaction now calls SobanleClient.createAutoOrder(customerData, targetAmount, cb) before writing an AdminTransaction. The transaction's amount is set from the real Sổ Bán Lẻ order total (order.orderTotal) rather than the admin's raw input amount, and sobanleOrderId is stored for reconciliation. On Sổ Bán Lẻ failure, returns 502 {code:"99", data:"SOBANLE_ORDER_FAILED"} with no DB row written. The success response contract ({code:"00", data:{merTrxId, paymentUrl}}) is unchanged. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KPzWwuTEeX2vXGXvyGn4q
tdgiang authored -
Co-Authored-By:
Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KPzWwuTEeX2vXGXvyGn4q
tdgiang authored -
Orchestrates product selection via productComboPicker and sale creation, failing gracefully if no product combo matches the target amount. Co-Authored-By:
Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KPzWwuTEeX2vXGXvyGn4q
tdgiang authored -
tdgiang authored
-
Two rulings made during Task 4 execution (see ledger): the early-refresh headroom now scales with token TTL instead of a flat 60s (a flat skew made the test's short-TTL token already "expired" the instant it was cached), and every scratch script that requires config/config.js now sets NODE_ENV before requiring it (the app's real entrypoint always resolves this via config/init first; the plan's scratch scripts had bypassed that). Co-Authored-By:
Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KPzWwuTEeX2vXGXvyGn4q
tdgiang authored -
tdgiang authored
-
Co-Authored-By:
Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KPzWwuTEeX2vXGXvyGn4q
tdgiang authored -
tdgiang authored
-
tdgiang authored
-
Co-Authored-By:
Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KPzWwuTEeX2vXGXvyGn4q
tdgiang authored -
Adds GET /admin index redirect, createdAt date-range filtering on the transactions list with a stat strip (total/success/pending/revenue) and client-side search, plus inline validation and quick amount chips on the new-transaction form. Co-Authored-By:
Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KPzWwuTEeX2vXGXvyGn4q
tdgiang authored
-
- 30 Aug, 2026 4 commits
-
-
Trust the single nginx reverse-proxy hop (confirmed in deploy.md) so express-rate-limit's per-client bucketing on POST /admin/login sees the real client IP instead of nginx's. Also fix a dead cookieSecure check (NODE_ENV === 'secure' never matched) so the session cookie actually gets Secure in production, verified live with X-Forwarded-Proto: https. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
# Conflicts: # app/views/admin/transactions-list.server.view.html # app/views/admin/transactions-new.server.view.html
tdgiang authored -
Applies a cohesive visual system to the admin panel: a navy/blue dashboard style (Inter font) for the internal staff pages, and a navy/gold fintech-trust style (IBM Plex Sans) for the customer-facing payment pages. Preserves all existing form fields, MegaPay integration markup, and Swig template bindings unchanged.
tdgiang authored -
Async bcryptjs measured to still not yield the event loop for realistic hash costs (~70ms compares finish before its 100ms yield threshold), so a login flood could still stall the same process's live MegaPay payment webhooks. Caps each client (or shared-proxy-bucket, see known limitation below) to 5 POST /admin/login attempts per rolling 60s window via express-rate-limit; requests over the limit get a 429 with a Vietnamese error and never reach adminAuth.login, so the bcrypt compare never runs. Known limitation: this app has no app.set('trust proxy', ...) configured and runs behind a reverse proxy in production, so express-rate-limit's default req.ip-based bucketing will key off the proxy's address, not the real client IP. In production this enforces "5 attempts/minute in aggregate behind the proxy" rather than "5 per real client IP" — an accepted trade-off for this low-traffic internal tool, but not the same guarantee trust proxy + per-IP limiting would give. Configuring trust proxy is an infrastructure change, left out of scope here.tdgiang authored
-
- 29 Aug, 2026 13 commits
-
-
tdgiang authored
-
Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
tdgiang authored
-
tdgiang authored
-
Appends accountsList, createAccount, toggleAccount, and resetAccountPassword to adminAuth.server.controller.js, adds the accounts-list view, and wires the /admin/accounts* routes behind requireLogin + requireAdmin. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
createTransaction now stamps createdByUsername from the session. listTransactions scopes results to the logged-in staff's own transactions, or (for admins) all transactions with an optional ?staff= filter sourced from real AdminUser records - the filter is ignored for non-admin sessions so staff cannot view another account's data by editing the query string. Transaction routes now use requireLogin instead of basicAuth, which is now unused and deleted. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
Adds AdminTransaction.createdByUsername (default null) so future permission-scoped views can attribute data to a user, plus a new app/libs/adminBootstrap.js that seeds the first admin account from ADMIN_USER/ADMIN_PASSWORD on boot and backfills any pre-existing transaction lacking createdByUsername to that admin. Wired into server.js's mongoose 'open' handler. Idempotent across repeated boots. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
Implement two authentication and authorization middlewares: - requireLogin: checks req.session.userId and responds with 302 redirect to /admin/login for HTML requests, or 401 JSON for API requests - requireAdmin: checks req.session.role === "admin" and responds with 403 for unauthorized access Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
Add passwordHash utility module wrapping bcryptjs for secure password hashing, and AdminUser Mongoose model with username (unique, lowercase), passwordHash, role (admin/staff), and active fields. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
tdgiang authored
-
tdgiang authored
-
# Conflicts: # .gitignore
tdgiang authored
-
- 28 Aug, 2026 12 commits
-
-
tdgiang authored
-
Adds listTransactions controller action and its Swig view, and creates app/routes/admin.server.routes.js to finally wire every admin controller function (Tasks 7-9) to real HTTP routes via the app's glob-based route loader. basicAuth protects /admin/transactions and /admin/transactions/new; the pay page, epay return, and epay IPN endpoints stay public. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
tdgiang authored
-
Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
Implements Task 7: newTransactionForm and createTransaction controller functions with supporting view. - Controller generates merTrxId and transCode with UUID-based unique suffix - Signs transaction using epaySign.signRequest - Persists AdminTransaction record to MongoDB - Returns JSON response with code 00/99 and payment URL - View provides HTML form to submit customer data and display payment link Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
Implements signRequest and signResponse functions that compute MegaPay/Epay HMAC-SHA256 signatures per MGP_Merchant_Interface specification sections 5.1 and 5.3. These functions will be consumed by Tasks 7 and 9 of the admin transaction management feature. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
tdgiang authored
-
Add mongoUri and admin.{user,password} config keys to config/env/all.js for Task 2 admin transaction management feature. Follows existing env var pattern used for payment provider credentials. Default mongoUri points to Docker service; admin credentials read from ADMIN_USER/ADMIN_PASSWORD env. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
tdgiang authored -
tdgiang authored
-
tdgiang authored
-