Repository navigation
Rate limiting for mutating API routes, real OrderEntry balances, and TradingEngine persistence - #158
Merged
akargi merged 6 commits intoNov 5, 2026
Conversation
Add a fixed-window API rate limiter (src/lib/api-rate-limit.ts) that runs before any mutating route handler. It mirrors the trading engine's windowMs/maxRequests pattern, keys buckets per endpoint and per caller (authenticated client id, falling back to forwarded/real IP), sweeps expired entries periodically, and returns 429 with a Retry-After header plus X-RateLimit-* headers when the limit is exceeded. Limits are configurable per endpoint programmatically and via API_RATE_LIMIT_<ENDPOINT> environment variables (see .env.example), with a default tier for unlisted endpoints. Applied to all mutating API endpoints: POST /api/v1/orders, POST /api/v1/orders/batch, DELETE /api/v1/orders/[id], POST /api/v1/payments, POST /api/v1/payments/webhook, POST /api/v1/analytics/events, POST /api/v1/admin/disputes, DELETE /api/v1/admin/listings and PATCH /api/v1/admin/users. Closes Chulilee#60
OrderEntry no longer falls back to a hardcoded 10000 USD / 1 BTC mock. The actual available account balance arrives via props (quoteBalance / baseBalance, with optional quoteCurrency / baseCurrency labels), percentage shortcuts size against those balances, and the component shows the available balance for the active side in the UI. TradingDashboard wires the balances from the portfolio service (getHoldings) - the USD value of stablecoin holdings as the quote balance, debited/credited as orders are placed - and passes them into OrderEntry. Closes Chulilee#61
…starts Add a persistence layer for the TradingEngine: a small synchronous TradingPersistence contract plus FileTradingPersistence (atomic JSON snapshot on disk) and InMemoryTradingPersistence backends, selected via TRADING_PERSISTENCE (file|memory|none) and TRADING_STATE_PATH or programmatically through the TradingEngine constructor. Every mutating path (order submit, batch submit, cancel) snapshots the full engine state. On startup the engine restores orders, fills, the trade tape, the per-client order index, and rebuilds the resting order books from open/partial_fill limit orders, so the book survives a restart with no events emitted during recovery. The app singleton (getTradingEngine) restores from the configured backend; under NODE_ENV=test persistence defaults to none so unit tests stay hermetic and direct construction remains in-memory. The default snapshot file is git-ignored. Closes Chulilee#62
Add TRADING_PERSISTENCE / TRADING_STATE_PATH and the API_RATE_LIMIT_* override variables to .env.example. Refs Chulilee#60, Chulilee#62
|
@akargi is attempting to deploy a commit to the Akargi Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
createTradingPersistenceFromEnv now accepts a plain string map so callers do not need to cast partial env objects to NodeJS.ProcessEnv.
next/server requires the global Request, which jsdom does not provide; the route-handler suites already use the node environment docblock.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes three open issues on the trading stack:
1. API layer rate limiting (closes #60)
The trading engine enforced rate limits internally, but the API layer accepted unlimited requests before they ever reached it. This adds a fixed-window API rate limiter (
src/lib/api-rate-limit.ts) that mirrors the engine'swindowMs/maxRequestspattern:setApiRateLimitConfig()and via environment variables (API_RATE_LIMIT_DEFAULT,API_RATE_LIMIT_ORDERS_CREATE, … — see.env.example).x-forwarded-for/x-real-ip, thenanonymous).Retry-AfterandX-RateLimit-*headers are set on rejection.POST /api/v1/orders,POST /api/v1/orders/batch,DELETE /api/v1/orders/[id],POST /api/v1/payments,POST /api/v1/payments/webhook,POST /api/v1/analytics/events,POST /api/v1/admin/disputes,DELETE /api/v1/admin/listings,PATCH /api/v1/admin/users.Retry-Afterheader.2. OrderEntry real balances (closes #61)
The percentage buttons (25/50/75/100%) used a hardcoded mock balance (10,000 USD / 1 BTC). Now:
OrderEntryreceivesquoteBalance/baseBalanceprops (plus optionalquoteCurrency/baseCurrencylabels).available-balancetest id).TradingDashboardwires the balances from the portfolio service (getHoldings: USD value of stablecoin holdings as quote), debits/credits them as orders are placed, and passes them intoOrderEntry.3. TradingEngine persistence (closes #62)
All engine state was in-memory only, so the order book and trade history were lost on restart. Now:
src/lib/trading-persistence.ts) withFileTradingPersistence(atomic JSON snapshot via temp-file + rename) andInMemoryTradingPersistencebackends.TRADING_PERSISTENCE(file|memory|none) andTRADING_STATE_PATH, or programmatically through theTradingEngineconstructor; defaults tofilein the app singleton (getTradingEngine) andnoneunderNODE_ENV=testso unit tests stay hermetic..trading-engine-state.json) is git-ignored.Test coverage
New unit tests cover the rate limiter (limits, per-endpoint/client buckets, 429 +
Retry-After), engine persistence (book/orders/trade-tape restore across a simulated restart, file backend round-trip, env selection) and the OrderEntry balance props (display, real-balance sizing, zero-balance behavior). CI was not run locally per the author''s workflow; tests run in CI.Closes #60, closes #61, closes #62