GSCX Platform — Technical Documentation
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.
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
- Browser fetches
/→ Express servespublic/index.html. - SPA bootstraps: calls
POST /api/initto check if admin setup is required. - User authenticates → receives a session token stored in
sessionStorage. - All subsequent API calls send the token as
x-session-tokenheader. - On every navigation the SPA calls
refreshState()— a singlePromise.allthat fetches all relevant data for the logged-in member. render()re-renders the entire#appdiv, thenbindEvents()re-attachesdata-actionlisteners.
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
POST /api/auth/loginwith{ email, password }.- If MFA is enabled the server returns
{ requiresOtp: true, otpType }— the client must re-submit with{ email, password, otpCode }. - Supported MFA types:
TOTP(RFC 6238, 30-second window ±1 step),CUSTOM(static OTP code set by admin). - On success:
{ sessionToken, member }is returned. The frontend storessessionTokeninsessionStorage.
TOTP Setup
POST /api/auth/totp/setup→ returns{ secret, otpauthUrl }. Secret is Base32-encoded using a built-in HMAC-SHA1 implementation (no external libs).- User scans QR code in an authenticator app.
POST /api/auth/totp/enablewith a live token to confirm and activate.
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.
| Role | Key Capabilities | Nav Views |
|---|---|---|
| ADMIN | Full access — member approval, KYC verification, compliance flags, reconciliation, all reports | All views |
| REMITTER | Create beneficiaries, submit remittances, track payments | Remittance Center |
| IMPORTER | Place import orders, track customs status, manage payout accounts | Import Center |
| EXPORTER | Maintain export profile, create shipments, list products | Export Center, Product Hub |
| TRANSPORT | Create & track shipments, log events, record charges, upload POD | Transport Center |
| INSURANCE | Issue quotes, bind policies, process claims | Insurance Center |
| BANK | Manage accounts & transactions, FX quotes, compliance flags | Bank Center |
| INSPECTOR | File inspection reports, upload evidence, log defects, set approval signal | Inspector Center |
| All logged-in | Crypto wallets, transfers, invoices, market data | Crypto 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.
| Column | Type | Notes |
|---|---|---|
id | VARCHAR(32) | PK, format ADM-XXXXXXX or role-prefix |
name | VARCHAR(255) | Display name |
category | TEXT (JSON array) | e.g. ["REMITTER","IMPORTER"] |
status | ENUM | PENDING · APPROVED · REJECTED |
kyc_status | ENUM | NOT_STARTED · SUBMITTED · VERIFIED · FAILED |
membership_fee_paid | TINYINT(1) | Boolean |
ofac_status | ENUM | CLEARED · FLAGGED · NOT_CHECKED |
password_hash | VARCHAR(128) | SHA-256 of password |
otp_type | VARCHAR(10) | NONE · TOTP · CUSTOM |
totp_secret | VARCHAR(64) | Base32 TOTP secret, never returned to client |
kyc_document_path | VARCHAR(500) | Server filesystem path to uploaded KYC file |
Data Model — Products
products
Marketplace listings created by Exporters. Supports trade classification fields.
| Column | Type | Notes |
|---|---|---|
id | VARCHAR(32) | PK |
exporter_id | VARCHAR(32) | FK → members |
category | ENUM | Machinery · Equipment · Hardware · Software · Commodities · Merchandize |
hs_code | VARCHAR(20) | Harmonised System commodity code |
eccn | VARCHAR(20) | Export Control Classification Number (EAR) |
dual_use | TINYINT(1) | Flag for dual-use goods requiring export licence |
incoterms | ENUM | EXW · FCA · CIF · FOB etc. |
ofac_status | ENUM | CHECKED · NOT_CHECKED |
rating | DECIMAL(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: Quote → Policy → Claim.
| Table | Key Fields |
|---|---|
insurance_quotes | coverage_type (ALL_RISK/NAMED_PERILS/TOTAL_LOSS), insured_value, premium, valid_until |
insurance_policies | policy_number, certificate_url, covered_from/until, risk_level, risk_notes |
insurance_claims | incident_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:
- BLOCK — hard block, prevents any new remittance, bank transaction, or payment
- HIGH / MEDIUM / LOW — informational, do not gate operations
Flags flow through: OPEN → UNDER_REVIEW → RESOLVED or ESCALATED.
Data Model — Inspection
| Table | Purpose |
|---|---|
inspection_reports | Primary report. Result: PASS / FAIL / CONDITIONAL_PASS. Approval signal: APPROVED / FAILED / PENDING — used to gate payment release. |
inspection_evidence | URLs to photos or videos attached to a report. |
inspection_defects | Structured defect log with type (COSMETIC/FUNCTIONAL/CRITICAL), severity, and % affected. |
Data Model — Crypto / MooChedda
| Table | Key Fields |
|---|---|
crypto_wallets | address (130-char secp256k1), private_key (platform-managed only), mnemonic, token_balances (JSON), wallet_type (PLATFORM/SELF_CUSTODY) |
crypto_transfers | from/to address, amount, token_symbol, moochedda_tx_id, optional linked_type/linked_id to any platform record |
crypto_invoices | moochedda_invoice_id, payment_url, line_items (JSON), tax_rate, total_amount, expiry, status (PENDING/PAID/EXPIRED) |
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.
| Method | Path | Description |
|---|---|---|
| GET | /health | DB ping. Returns { ok: true } |
| POST | /init | Bootstrap check. Returns { requiresAdminSetup } |
| POST | /admin/setup | Create first admin account (one-time). Body: name, email, password |
API Reference — Auth
| Method | Path | Description |
|---|---|---|
| POST | /auth/register | Register new member. Body: name, email, country, password, categories[] |
| POST | /auth/login | Sign in. Body: email, password[, otpCode]. Returns sessionToken |
| POST | /auth/logout | Invalidate session token |
| POST | /auth/settings | Change password or custom OTP code |
| POST | /auth/totp/setup | Generate TOTP secret. Returns { secret, otpauthUrl } |
| POST | /auth/totp/enable | Activate TOTP by confirming with live code |
API Reference — Members
| Method | Path | Description |
|---|---|---|
| GET | /members | List all members |
| POST | /members | Create member (admin) |
| PATCH | /members/:id | Update status, KYC status, OFAC status, licence status |
| POST | /kyc/upload | Upload KYC document (multipart/form-data) |
| GET | /kyc/document/:memberId | Download KYC document (admin only) |
API Reference — Products
| Method | Path | Description |
|---|---|---|
| GET | /products | List products. Query: exporterId, category, search |
| POST | /products | Create product listing |
| PATCH | /products/:id/ofac | Set OFAC status |
| PATCH | /products/:id/rate | Submit star rating (1–5). Computes running average |
API Reference — Import Orders
| Method | Path | Description |
|---|---|---|
| GET | /import-orders | List. Query: importerId |
| POST | /import-orders | Submit import order. Full customs declaration required |
| PATCH | /import-orders/:id/status | Update status (admin/bank) |
| PATCH | /import-orders/:id/ofac | Set OFAC screening result |
API Reference — Export
| Method | Path | Description |
|---|---|---|
| GET | /export-profiles | Get exporter entity profile |
| POST | /export-profiles | Create/upsert export profile |
| GET | /export-shipments | List shipments. Query: exporterId |
| POST | /export-shipments | Create export shipment |
| PATCH | /export-shipments/:id/status | Advance shipment status |
| PATCH | /export-shipments/:id/ofac | Set OFAC status |
| GET | /payout-accounts | List payout accounts. Query: memberId |
| POST | /payout-accounts | Add bank or crypto payout account |
| DELETE | /payout-accounts/:id | Remove payout account |
API Reference — Remittance
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.| Method | Path | Description |
|---|---|---|
| GET | /beneficiaries | List beneficiaries. Query: remitterId |
| POST | /beneficiaries | Create beneficiary (bank/crypto/internal) |
| DELETE | /beneficiaries/:id | Delete beneficiary |
| GET | /remittances | List remittances. Query: remitterId |
| POST | /remittances | Submit remittance. Compliance-gated. |
| PATCH | /remittances/:id/status | Update status |
| PATCH | /remittances/:id/ofac | Set OFAC status |
API Reference — Transport
| Method | Path | Description |
|---|---|---|
| GET | /transport-shipments | List. Query: transportId |
| POST | /transport-shipments | Create shipment. Tracking number required. |
| PATCH | /transport-shipments/:id/status | Update shipment status |
| PATCH | /transport-shipments/:id/customs | Update customs status and notes |
| PATCH | /transport-shipments/:id/pod | Record proof of delivery |
| GET | /shipment-events | List events. Query: shipmentId, transportId |
| POST | /shipment-events | Log tracking event |
| GET | /shipment-charges | List charges. Query: shipmentId |
| POST | /shipment-charges | Add charge (duties, brokerage, etc.) |
| PATCH | /shipment-charges/:id/status | Mark charge PAID or WAIVED |
API Reference — Insurance
| Method | Path | Description |
|---|---|---|
| GET | /insurance-quotes | List. Query: insurerId |
| POST | /insurance-quotes | Create quote |
| PATCH | /insurance-quotes/:id/status | Accept or reject quote |
| GET | /insurance-policies | List. Query: insurerId |
| POST | /insurance-policies | Bind policy from accepted quote |
| PATCH | /insurance-policies/:id/status | Update policy status |
| PATCH | /insurance-policies/:id/risk | Update risk level and notes |
| GET | /insurance-claims | List. Query: insurerId, policyId |
| POST | /insurance-claims | File claim against a policy |
| PATCH | /insurance-claims/:id/status | Approve, 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.| Method | Path | Description |
|---|---|---|
| GET | /bank-accounts | List. Query: bankId, memberId |
| POST | /bank-accounts | Open account. Body: bankId, memberId, accountNumber, accountType, currency |
| PATCH | /bank-accounts/:id/balance | Adjust available and ledger balances |
| PATCH | /bank-accounts/:id/status | Freeze or close account |
| GET | /bank-transactions | List. Query: bankId, accountId |
| POST | /bank-transactions | Record transaction. Compliance-gated. |
| PATCH | /bank-transactions/:id/status | Settle, fail, or reverse |
| GET | /fx-quotes | List FX quotes. Query: bankId |
| POST | /fx-quotes | Create FX quote with rate, spread, and fees |
| PATCH | /fx-quotes/:id/execute | Execute quote — locks rate, creates bank transaction |
| PATCH | /fx-quotes/:id/status | Expire or cancel quote |
API Reference — Compliance
| Method | Path | Description |
|---|---|---|
| GET | /compliance-flags | List flags. Query: bankId, referenceType, referenceId |
| POST | /compliance-flags | Raise flag. Body: bankId, referenceType, referenceId, flagType, severity, description |
| PATCH | /compliance-flags/:id/status | Update status (UNDER_REVIEW, RESOLVED, ESCALATED) |
API Reference — Payment Routing
| Method | Path | Description |
|---|---|---|
| POST | /payment/validate-rail | Validate payload for a given rail without persisting |
| GET | /payment/rails | Return RAIL_SPECS with all rail constraints |
| GET | /payment/routes | List stored route requests. Query: requestedBy |
| POST | /payment/route | Score all eligible rails for a payment. Stores result. Body: requestedBy, fromCurrency, toCurrency, amount, recipientType, urgency |
| PATCH | /payment/routes/:id/execute | Execute recommended rail — creates bank transaction |
API Reference — Reconciliation
| Method | Path | Description |
|---|---|---|
| GET | /reconciliation/runs | List all reconciliation runs |
| GET | /reconciliation/entries | List entries for a run. Query: runId |
| POST | /reconciliation/run | Trigger a new run. Returns 202 immediately; runs via setImmediate. Body: scope, notes |
API Reference — Inspection
| Method | Path | Description |
|---|---|---|
| GET | /inspection-reports | List. Query: inspectorId, referenceType, referenceId |
| POST | /inspection-reports | Create report. Body: inspectorId, referenceType, referenceId, inspectionDate, result, approvalSignal |
| PATCH | /inspection-reports/:id | Update result, status, or approval signal |
| GET | /inspection-evidence | List. Query: inspectionId |
| POST | /inspection-evidence | Attach evidence URL. Body: inspectionId, fileUrl, type (PHOTO/VIDEO) |
| GET | /inspection-defects | List. Query: inspectionId |
| POST | /inspection-defects | Log defect. Body: inspectionId, defectType, severity[, percentageAffected] |
API Reference — Crypto / MooChedda
| Method | Path | Description |
|---|---|---|
| GET | /crypto/wallets | List wallets. Query: memberId |
| POST | /crypto/wallets/create | Generate new secp256k1 wallet via MooChedda. Returns address, private key, and mnemonic once. |
| POST | /crypto/wallets/recover | Restore wallet from BIP39 mnemonic |
| GET | /crypto/wallets/:id/balance | Fetch live token balances from MooChedda, cache in DB |
| GET | /crypto/transfers | Transfer history. Query: memberId |
| POST | /crypto/transfer | Execute token transfer. Signs with stored private key. Body: walletId, toAddress, amount, tokenSymbol |
| GET | /crypto/invoices | Invoice history. Query: memberId |
| POST | /crypto/invoices | Create hosted invoice. Body: walletId, lineItems[], taxRate?, expirationMinutes? |
| GET | /crypto/invoices/:id/status | Poll MooChedda for payment confirmation, sync status to DB |
| GET | /crypto/tokens | Live token registry from MooChedda |
| GET | /crypto/prices | Real-time USDT-denominated prices |
| GET | /crypto/deposit-instructions | ACH/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.
| Export | Signature | Description |
|---|---|---|
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?) → middleware | Express 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).
| Rail | Required Fields | Currency | Max Amount | Settlement |
|---|---|---|---|---|
| ACH | counterpartyAccount, counterpartyBank | USD only | $25M | 48h |
| SEPA | counterpartyAccount, counterpartySwift | EUR only | — | 24h |
| WIRE | counterpartyAccount, counterpartyBank | Any | — | 24h |
| SWIFT | counterpartyAccount, counterpartySwift | Any | — | 72h |
| INTERNAL | counterpartyAccount | Any | — | 0h |
| CRYPTO | counterpartyAccount (wallet address) | Any | — | 1h |
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
| Variable | Required | Description |
|---|---|---|
DB_HOST | Yes | MariaDB host |
DB_PORT | No (3306) | MariaDB port |
DB_USER | Yes | Database username |
DB_PASSWORD | Yes | Database password |
DB_NAME | Yes | Database name |
PORT | No (3000) | HTTP server port |
NODE_ENV | No | Set 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
crypto_wallets are stored in plaintext. Before going to production, encrypt using AES-256-GCM with a KMS key.style="" attributes. All presentation is via CSS classes — safe for a strict Content-Security-Policy response header.requireCompliance) runs on every remittance and bank transaction write, providing a last-line-of-defence check even if upstream UI validation is bypassed.