GSCX Platform — Technical Documentation

Stack: Node.js · Express · MariaDB · Vanilla JS SPA  |  March 2026

The Global Supply Chain Exchange (GSCX) is a multi-role trade finance and logistics platform. It connects Remitters, Importers, Exporters, Transport operators, Insurance providers, Banks, and Inspectors on a single secured application, with a real-time crypto payment layer powered by MooChedda.

Runtime
Node.js (CommonJS)
Framework
Express 4.x
Database
MariaDB / MySQL
Frontend
Vanilla JS SPA (no build)
Auth
Session token + TOTP
Crypto
MooChedda API (secp256k1)

Architecture

GSCX is a monolithic Node.js application. The backend exposes a REST API under /api. The frontend is a single HTML file (public/index.html) that loads public/app.js — a state-machine SPA using DOM re-rendering and data-action event delegation, no framework required.

Directory Layout

GSCXNodeJS/
├── src/
│   ├── server.js            Express entry point, static serving, /api mount
│   ├── db.js                MariaDB pool, query() helper
│   ├── routes/
│   │   └── api.js           All REST endpoints (~2 400 lines)
│   ├── services/
│   │   ├── compliance.js    Compliance flag checking + middleware
│   │   ├── paymentOrchestrator.js  Route scoring
│   │   ├── paymentRails.js  Rail normalisation + validation
│   │   ├── reconciliation.js  Ledger reconciliation engine
│   │   └── moochedda.js     MooChedda API wrapper (crypto payments)
│   └── sql/
│       └── schema.sql       CREATE TABLE + idempotent ALTER migrations
├── public/
│   ├── index.html           SPA shell
│   ├── app.js               Full frontend (~4 600 lines)
│   └── styles.css           CSS custom-property theming
├── Docs.html                This file
└── SystemOverview.html      Executive overview

Request Lifecycle

  1. Browser fetches / → Express serves public/index.html.
  2. SPA bootstraps: calls POST /api/init to check if admin setup is required.
  3. User authenticates → receives a session token stored in sessionStorage.
  4. All subsequent API calls send the token as x-session-token header.
  5. On every navigation the SPA calls refreshState() — a single Promise.all that fetches all relevant data for the logged-in member.
  6. render() re-renders the entire #app div, then bindEvents() re-attaches data-action listeners.

Authentication

GSCX uses a server-side session map (in-process Map). Sessions are not persisted across restarts. Each session stores the full member object. The token is a 48-character hex string from crypto.randomBytes(24).

Login Flow

  1. POST /api/auth/login with { email, password }.
  2. If MFA is enabled the server returns { requiresOtp: true, otpType } — the client must re-submit with { email, password, otpCode }.
  3. Supported MFA types: TOTP (RFC 6238, 30-second window ±1 step), CUSTOM (static OTP code set by admin).
  4. On success: { sessionToken, member } is returned. The frontend stores sessionToken in sessionStorage.

TOTP Setup

  1. POST /api/auth/totp/setup → returns { secret, otpauthUrl }. Secret is Base32-encoded using a built-in HMAC-SHA1 implementation (no external libs).
  2. User scans QR code in an authenticator app.
  3. POST /api/auth/totp/enable with a live token to confirm and activate.
Sessions are in-memory only. A server restart invalidates all active sessions. For production, sessions should be persisted to Redis or the database.

Roles & Permissions

A member's category is a JSON array (e.g. ["REMITTER","IMPORTER"]), so a single account can hold multiple roles. The SPA derives nav visibility from user.category.

RoleKey CapabilitiesNav Views
ADMINFull access — member approval, KYC verification, compliance flags, reconciliation, all reportsAll views
REMITTERCreate beneficiaries, submit remittances, track paymentsRemittance Center
IMPORTERPlace import orders, track customs status, manage payout accountsImport Center
EXPORTERMaintain export profile, create shipments, list productsExport Center, Product Hub
TRANSPORTCreate & track shipments, log events, record charges, upload PODTransport Center
INSURANCEIssue quotes, bind policies, process claimsInsurance Center
BANKManage accounts & transactions, FX quotes, compliance flagsBank Center
INSPECTORFile inspection reports, upload evidence, log defects, set approval signalInspector Center
All logged-inCrypto wallets, transfers, invoices, market dataCrypto Center

Member accounts start with status: PENDING and require admin approval (PATCH /api/members/:id) before they can transact. KYC document upload and OFAC screening are prerequisites for most operations.

Data Model — Members

members

Central identity table. Every other entity references this via foreign key.

ColumnTypeNotes
idVARCHAR(32)PK, format ADM-XXXXXXX or role-prefix
nameVARCHAR(255)Display name
categoryTEXT (JSON array)e.g. ["REMITTER","IMPORTER"]
statusENUMPENDING · APPROVED · REJECTED
kyc_statusENUMNOT_STARTED · SUBMITTED · VERIFIED · FAILED
membership_fee_paidTINYINT(1)Boolean
ofac_statusENUMCLEARED · FLAGGED · NOT_CHECKED
password_hashVARCHAR(128)SHA-256 of password
otp_typeVARCHAR(10)NONE · TOTP · CUSTOM
totp_secretVARCHAR(64)Base32 TOTP secret, never returned to client
kyc_document_pathVARCHAR(500)Server filesystem path to uploaded KYC file

Data Model — Products

products

Marketplace listings created by Exporters. Supports trade classification fields.

ColumnTypeNotes
idVARCHAR(32)PK
exporter_idVARCHAR(32)FK → members
categoryENUMMachinery · Equipment · Hardware · Software · Commodities · Merchandize
hs_codeVARCHAR(20)Harmonised System commodity code
eccnVARCHAR(20)Export Control Classification Number (EAR)
dual_useTINYINT(1)Flag for dual-use goods requiring export licence
incotermsENUMEXW · FCA · CIF · FOB etc.
ofac_statusENUMCHECKED · NOT_CHECKED
ratingDECIMAL(2,1)Computed star rating

Data Model — Trade Orders & Shipments

import_orders

Full customs-grade import declaration. Covers IOR identity, HS classification, regulatory flags (FDA/FCC/USDA), payment terms, and duty responsibilities.

export_profiles

One-per-exporter legal entity profile: registration number, tax ID, beneficial owners. Required before creating shipments.

export_shipments

Individual export consignment. Tracks ECCN, dual-use flag, port of loading, export licence, and customs clearance status.

beneficiaries & remittances

A Remitter defines beneficiaries (bank, crypto, or internal recipients) and then submits remittances against them. Remittances are compliance-gated via requireCompliance middleware — any BLOCK-severity flag on the member blocks submission with HTTP 403.

payout_accounts

Member-owned receiving accounts (bank or crypto) used for export proceeds and refunds.

Data Model — Transport

transport_shipments

Carrier-level shipment record. Links to an export or import order. Stores AWB, BOL, manifest URL, origin/destination addresses, cargo weight/volume, customs status, and proof-of-delivery fields (recipient name, signature URL, photo URL).

shipment_events

Event log per shipment: LABEL_CREATED → PICKED_UP → IN_TRANSIT → AT_CUSTOMS → OUT_FOR_DELIVERY → DELIVERED or EXCEPTION.

shipment_charges

Duties, brokerage, surcharges, and delivery fees. Each charge has a payer (EXPORTER / IMPORTER / PLATFORM) and a payment status.

Data Model — Insurance

Three-stage lifecycle: QuotePolicyClaim.

TableKey Fields
insurance_quotescoverage_type (ALL_RISK/NAMED_PERILS/TOTAL_LOSS), insured_value, premium, valid_until
insurance_policiespolicy_number, certificate_url, covered_from/until, risk_level, risk_notes
insurance_claimsincident_type, claimed_amount, approved_amount, payout_recipient, payout_status

Data Model — Banking & Payments

bank_accounts

Accounts opened by a Bank member on behalf of any member. Types: OPERATING · CUSTODIAL · ESCROW · TRUST. Tracks available_balance and ledger_balance separately.

bank_transactions

Credits and debits against a bank account. Supports all six payment rails: SWIFT · ACH · SEPA · WIRE · INTERNAL · CRYPTO. Compliance-gated at write time. Has a compliance_hold flag for post-booking freezes.

fx_quotes

FX conversion quotes with rate, spread (bps), and fees. Can be executed (PATCH /fx-quotes/:id/execute) to lock the rate and produce a linked transaction.

payment_routes

Scored routing recommendations. Stored per request with all route options as JSON. Can be executed to create a bank transaction.

Data Model — Compliance

compliance_flags

Raised by Bank users against members, transactions, payments, or accounts. Severity levels:

Flags flow through: OPEN → UNDER_REVIEW → RESOLVED or ESCALATED.

Data Model — Inspection

TablePurpose
inspection_reportsPrimary report. Result: PASS / FAIL / CONDITIONAL_PASS. Approval signal: APPROVED / FAILED / PENDING — used to gate payment release.
inspection_evidenceURLs to photos or videos attached to a report.
inspection_defectsStructured defect log with type (COSMETIC/FUNCTIONAL/CRITICAL), severity, and % affected.

Data Model — Crypto / MooChedda

TableKey Fields
crypto_walletsaddress (130-char secp256k1), private_key (platform-managed only), mnemonic, token_balances (JSON), wallet_type (PLATFORM/SELF_CUSTODY)
crypto_transfersfrom/to address, amount, token_symbol, moochedda_tx_id, optional linked_type/linked_id to any platform record
crypto_invoicesmoochedda_invoice_id, payment_url, line_items (JSON), tax_rate, total_amount, expiry, status (PENDING/PAID/EXPIRED)
Security: Private keys are stored in plaintext in this build. In production, encrypt at rest using AES-256-GCM with a KMS-managed key before persisting to crypto_wallets.private_key.

API Reference — System

Base path: /api. All requests and responses are JSON. Session token sent as x-session-token header or sessionToken in request body.

MethodPathDescription
GET/healthDB ping. Returns { ok: true }
POST/initBootstrap check. Returns { requiresAdminSetup }
POST/admin/setupCreate first admin account (one-time). Body: name, email, password

API Reference — Auth

MethodPathDescription
POST/auth/registerRegister new member. Body: name, email, country, password, categories[]
POST/auth/loginSign in. Body: email, password[, otpCode]. Returns sessionToken
POST/auth/logoutInvalidate session token
POST/auth/settingsChange password or custom OTP code
POST/auth/totp/setupGenerate TOTP secret. Returns { secret, otpauthUrl }
POST/auth/totp/enableActivate TOTP by confirming with live code

API Reference — Members

MethodPathDescription
GET/membersList all members
POST/membersCreate member (admin)
PATCH/members/:idUpdate status, KYC status, OFAC status, licence status
POST/kyc/uploadUpload KYC document (multipart/form-data)
GET/kyc/document/:memberIdDownload KYC document (admin only)

API Reference — Products

MethodPathDescription
GET/productsList products. Query: exporterId, category, search
POST/productsCreate product listing
PATCH/products/:id/ofacSet OFAC status
PATCH/products/:id/rateSubmit star rating (1–5). Computes running average

API Reference — Import Orders

MethodPathDescription
GET/import-ordersList. Query: importerId
POST/import-ordersSubmit import order. Full customs declaration required
PATCH/import-orders/:id/statusUpdate status (admin/bank)
PATCH/import-orders/:id/ofacSet OFAC screening result

API Reference — Export

MethodPathDescription
GET/export-profilesGet exporter entity profile
POST/export-profilesCreate/upsert export profile
GET/export-shipmentsList shipments. Query: exporterId
POST/export-shipmentsCreate export shipment
PATCH/export-shipments/:id/statusAdvance shipment status
PATCH/export-shipments/:id/ofacSet OFAC status
GET/payout-accountsList payout accounts. Query: memberId
POST/payout-accountsAdd bank or crypto payout account
DELETE/payout-accounts/:idRemove payout account

API Reference — Remittance

All POST /remittances requests pass through requireCompliance(req => req.body.remitterId). Any BLOCK-severity compliance flag on the remitter returns HTTP 403 before the handler runs.
MethodPathDescription
GET/beneficiariesList beneficiaries. Query: remitterId
POST/beneficiariesCreate beneficiary (bank/crypto/internal)
DELETE/beneficiaries/:idDelete beneficiary
GET/remittancesList remittances. Query: remitterId
POST/remittancesSubmit remittance. Compliance-gated.
PATCH/remittances/:id/statusUpdate status
PATCH/remittances/:id/ofacSet OFAC status

API Reference — Transport

MethodPathDescription
GET/transport-shipmentsList. Query: transportId
POST/transport-shipmentsCreate shipment. Tracking number required.
PATCH/transport-shipments/:id/statusUpdate shipment status
PATCH/transport-shipments/:id/customsUpdate customs status and notes
PATCH/transport-shipments/:id/podRecord proof of delivery
GET/shipment-eventsList events. Query: shipmentId, transportId
POST/shipment-eventsLog tracking event
GET/shipment-chargesList charges. Query: shipmentId
POST/shipment-chargesAdd charge (duties, brokerage, etc.)
PATCH/shipment-charges/:id/statusMark charge PAID or WAIVED

API Reference — Insurance

MethodPathDescription
GET/insurance-quotesList. Query: insurerId
POST/insurance-quotesCreate quote
PATCH/insurance-quotes/:id/statusAccept or reject quote
GET/insurance-policiesList. Query: insurerId
POST/insurance-policiesBind policy from accepted quote
PATCH/insurance-policies/:id/statusUpdate policy status
PATCH/insurance-policies/:id/riskUpdate risk level and notes
GET/insurance-claimsList. Query: insurerId, policyId
POST/insurance-claimsFile claim against a policy
PATCH/insurance-claims/:id/statusApprove, deny, or mark paid

API Reference — Banking

POST /bank-transactions is compliance-gated on both the bank member and the account (requireCompliance(bankId, accountId)). Frozen or closed accounts are blocked at the compliance layer.
MethodPathDescription
GET/bank-accountsList. Query: bankId, memberId
POST/bank-accountsOpen account. Body: bankId, memberId, accountNumber, accountType, currency
PATCH/bank-accounts/:id/balanceAdjust available and ledger balances
PATCH/bank-accounts/:id/statusFreeze or close account
GET/bank-transactionsList. Query: bankId, accountId
POST/bank-transactionsRecord transaction. Compliance-gated.
PATCH/bank-transactions/:id/statusSettle, fail, or reverse
GET/fx-quotesList FX quotes. Query: bankId
POST/fx-quotesCreate FX quote with rate, spread, and fees
PATCH/fx-quotes/:id/executeExecute quote — locks rate, creates bank transaction
PATCH/fx-quotes/:id/statusExpire or cancel quote

API Reference — Compliance

MethodPathDescription
GET/compliance-flagsList flags. Query: bankId, referenceType, referenceId
POST/compliance-flagsRaise flag. Body: bankId, referenceType, referenceId, flagType, severity, description
PATCH/compliance-flags/:id/statusUpdate status (UNDER_REVIEW, RESOLVED, ESCALATED)

API Reference — Payment Routing

MethodPathDescription
POST/payment/validate-railValidate payload for a given rail without persisting
GET/payment/railsReturn RAIL_SPECS with all rail constraints
GET/payment/routesList stored route requests. Query: requestedBy
POST/payment/routeScore all eligible rails for a payment. Stores result. Body: requestedBy, fromCurrency, toCurrency, amount, recipientType, urgency
PATCH/payment/routes/:id/executeExecute recommended rail — creates bank transaction

API Reference — Reconciliation

MethodPathDescription
GET/reconciliation/runsList all reconciliation runs
GET/reconciliation/entriesList entries for a run. Query: runId
POST/reconciliation/runTrigger a new run. Returns 202 immediately; runs via setImmediate. Body: scope, notes

API Reference — Inspection

MethodPathDescription
GET/inspection-reportsList. Query: inspectorId, referenceType, referenceId
POST/inspection-reportsCreate report. Body: inspectorId, referenceType, referenceId, inspectionDate, result, approvalSignal
PATCH/inspection-reports/:idUpdate result, status, or approval signal
GET/inspection-evidenceList. Query: inspectionId
POST/inspection-evidenceAttach evidence URL. Body: inspectionId, fileUrl, type (PHOTO/VIDEO)
GET/inspection-defectsList. Query: inspectionId
POST/inspection-defectsLog defect. Body: inspectionId, defectType, severity[, percentageAffected]

API Reference — Crypto / MooChedda

MethodPathDescription
GET/crypto/walletsList wallets. Query: memberId
POST/crypto/wallets/createGenerate new secp256k1 wallet via MooChedda. Returns address, private key, and mnemonic once.
POST/crypto/wallets/recoverRestore wallet from BIP39 mnemonic
GET/crypto/wallets/:id/balanceFetch live token balances from MooChedda, cache in DB
GET/crypto/transfersTransfer history. Query: memberId
POST/crypto/transferExecute token transfer. Signs with stored private key. Body: walletId, toAddress, amount, tokenSymbol
GET/crypto/invoicesInvoice history. Query: memberId
POST/crypto/invoicesCreate hosted invoice. Body: walletId, lineItems[], taxRate?, expirationMinutes?
GET/crypto/invoices/:id/statusPoll MooChedda for payment confirmation, sync status to DB
GET/crypto/tokensLive token registry from MooChedda
GET/crypto/pricesReal-time USDT-denominated prices
GET/crypto/deposit-instructionsACH/Wire fiat-to-USDC onramp details

Service — Compliance Engine

File: src/services/compliance.js

Provides programmatic compliance checks and an Express middleware factory used to gate write operations.

ExportSignatureDescription
checkMember(memberId) → { ok, blocked, flags, blockers }Check all active BLOCK flags for a member
checkAccount(accountId) → { ok, blocked, frozen, ... }Check flags + account FROZEN/CLOSED status
checkTransaction(txnId) → { ok, blocked, complianceHold, ... }Check flags + compliance_hold column
checkPaymentPath(memberId, accountId) → { ok, blocked, allFlags, ... }Combined member + account check for payment flows
requireCompliance(getMemberId, getAccountId?) → middlewareExpress middleware factory. Returns 403 if blocked. Attaches req.complianceResult on pass.

Service — Payment Orchestrator

File: src/services/paymentOrchestrator.js

Scores all eligible payment rails for a given request. No I/O — pure computation.

score = baseCost + (amount × feeRate) + (settlementHours × urgencyWeight)

urgencyWeight: STANDARD=0.5 · EXPRESS=1.5 · URGENT=4.0

Rails: INTERNAL (score ≈ 0) → CRYPTO → SEPA → ACH → WIRE → SWIFT (highest cost). Currency and recipient-type constraints filter ineligible rails before scoring.

Service — Payment Rails

File: src/services/paymentRails.js

Validates and normalises per-rail payloads. Each rail has a spec defining required fields, currency constraints, amount ceilings, and rail-specific metadata (SEC codes for ACH, message type for SWIFT, scheme for SEPA, network for CRYPTO).

RailRequired FieldsCurrencyMax AmountSettlement
ACHcounterpartyAccount, counterpartyBankUSD only$25M48h
SEPAcounterpartyAccount, counterpartySwiftEUR only24h
WIREcounterpartyAccount, counterpartyBankAny24h
SWIFTcounterpartyAccount, counterpartySwiftAny72h
INTERNALcounterpartyAccountAny0h
CRYPTOcounterpartyAccount (wallet address)Any1h

Service — Reconciliation Engine

File: src/services/reconciliation.js

Triggered via POST /reconciliation/run. Runs asynchronously via setImmediate after the 202 response is sent. Compares platform ledger records against bank transactions using amount tolerance of ±$0.01.

Scopes: FULL · REMITTANCES · IMPORTS · EXPORTS · ACCOUNTS. Results written to reconciliation_entries with one of: MATCHED · UNMATCHED · DISCREPANCY · NO_BANK_TXN.

Service — MooChedda SDK

File: src/services/moochedda.js

Zero external dependencies — uses Node built-in crypto, https, and http modules.

Signing

Transfer payloads are signed with secp256k1 ECDSA. The DER key is built programmatically from the 32-byte private key hex using ASN.1 encoding — no secp256k1 npm package required. The hash is SHA-256 of the concatenated string fromAddress + toAddress + amount + tokenSymbol.

TLS

Connections to v1.moochedda.com:3002 use rejectUnauthorized: false to tolerate custom certificates on the MooChedda host. This should be tightened in production by pinning the server certificate.

Environment Variables

VariableRequiredDescription
DB_HOSTYesMariaDB host
DB_PORTNo (3306)MariaDB port
DB_USERYesDatabase username
DB_PASSWORDYesDatabase password
DB_NAMEYesDatabase name
PORTNo (3000)HTTP server port
NODE_ENVNoSet to production for prod start script

Database Initialisation

# First run — create tables and optionally seed data
node src/seed.js

# Or run the server directly; schema.sql runs on startup
npm run dev        # development
npm start          # production (NODE_ENV=production)

The schema file uses CREATE TABLE IF NOT EXISTS and ALTER TABLE … ADD COLUMN IF NOT EXISTS throughout, so re-running it against an existing database is safe and idempotent.

Security Notes

Private keys in crypto_wallets are stored in plaintext. Before going to production, encrypt using AES-256-GCM with a KMS key.
Passwords are hashed with SHA-256 (no salt). Replace with bcrypt or Argon2 for production.
Sessions are in-process memory. A server restart invalidates all sessions. Use Redis or a DB-backed session store for production.
TOTP secrets are stored in the database. Ensure the DB connection uses TLS and the DB is not publicly accessible.
CSP: The frontend uses zero inline style="" attributes. All presentation is via CSS classes — safe for a strict Content-Security-Policy response header.
Compliance middleware (requireCompliance) runs on every remittance and bank transaction write, providing a last-line-of-defence check even if upstream UI validation is bypassed.
Global Supply Chain Exchange — Technical Documentation — March 2026 — Confidential