Skip to content

chore(release): promote develop to stable v1.2.0#162

Open
jeziellopes wants to merge 141 commits intomainfrom
develop
Open

chore(release): promote develop to stable v1.2.0#162
jeziellopes wants to merge 141 commits intomainfrom
develop

Conversation

@jeziellopes
Copy link
Copy Markdown
Owner

Release promotion: developmain

Merging all P0 + P1 work shipped since v1.1.0 (Apr 4). Semantic-release will compute v1.2.0 from the feat( commits.


What's new since v1.1.0

Features

Performance

Bug fixes

  • Order book depth bar fills right-to-left on both sides; asks sorted best-ask nearest spread
  • Gap detection + snapshot staleness check for order book sync integrity
  • Stream subscriptions aligned with Binance spot reference spec
  • Chart zoom: replace fitContent() with setVisibleLogicalRange anchored to last 100 bars

Design system


Stats

  • 349 tests passing (was ~190 at v1.1.0)
  • Build: clean, < 200 KB gzip initial bundle
  • TypeScript: strict mode, zero errors

jeziellopes and others added 30 commits April 3, 2026 23:08
GitHub merge commits (Merge pull request #N) have 2 parents and
cannot be signed off by authors. Filter them out before checking
for Signed-off-by so release PRs (develop → main) don't fail DCO.

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
Updated README to include badges for tests, code quality, and DCO with improved formatting.
- Domain ports: MarketDataSource, ConnectionStatus, OrderBook types
- Domain book sync: pure bookFromSnapshot + applyDepthUpdate functions
- Infrastructure: BinanceDataSource adapter with WS lifecycle, depth buffer, snapshot sequencing
- Infrastructure: exponential backoff reconnect manager
- Application: Zustand market-data store with RAF batching and selector hooks
- Config singleton factory for dependency injection
- 31 new tests, 100% coverage on domain/infra, 97.6% on stores

Closes #99

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
feat(infra): WebSocket data layer — Binance live market data
# [1.1.0-next.2](v1.1.0-next.1...v1.1.0-next.2) (2026-04-04)

### Features

* **infra:** WebSocket data layer — Binance live market data ([35791df](35791df)), closes [#99](#99)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
…admap

Closes: companion to #100 merge
Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
…ption

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
- Reorganize imports in book-sync.ts, BinanceDataSource.ts, snapshot.ts,
  ws-client.ts, reconnect.test.ts, config.ts, market-data.ts, market-data.test.ts
- Refactor theme-dropdown.tsx migration block to store getItem result in
  local var instead of using non-null assertion

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
docs(readme): mark WebSocket data layer shipped, sync roadmap
# [1.1.0-next.3](v1.1.0-next.2...v1.1.0-next.3) (2026-04-04)

### Bug Fixes

* **lint:** resolve Biome import-order and noNonNullAssertion violations ([03d7c04](03d7c04))

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
- Add loader to /symbol/$symbol that validates ticker (uppercase normalize),
  throws notFound() for unknown symbols, and triggers market data init
- Add validateSearch with Zod schema: tab (book|trades|depth), levels (number)
  with catch-based defaults (tab='book', levels=20)
- Add notFoundComponent with 404 page and link back to BTCUSDT
- Add beforeLoad redirect on / → /symbol/BTCUSDT (AC-8)
- Wire useConnectionStatus() to LiveIndicator in __root.tsx (replaces hardcoded)
- Add normalizeSymbol(), isValidSymbol() helpers to lib/symbols.ts
- Add pricePrecision, qtyPrecision fields to SymbolInfo and all 18 entries
- Create stores/ui.ts — Zustand slice for active tab + levels, synced from URL
- Pass tab/levels as props through TerminalLayout (wired, ready for #96)

Closes #98

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
Replace 'as never' with 'as any' (matching index.tsx pattern) so
TypeScript doesn't infer the entire route config as never. Add explicit
type annotations on loader params and cast useLoaderData/useSearch
return types to their concrete types.

Fixes: Property does not exist on type 'never' errors in Vercel build.
Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
…er types

The redirect() call inside the loader needs both 'to' and 'params' cast
as never — matching the established pattern in index.tsx. Casting only
'to' as any left params unresolved against the router's generated types,
causing build failure: 'symbol does not exist in type ParamsReducerFn'.

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
TanStack Router skips beforeLoad on cached route matches, so the / -> BTCUSDT
redirect was silently ignored when clicking the logo from a symbol page.
Fix: link directly to /symbol/BTCUSDT instead of routing through /.
The beforeLoad redirect on / remains as a fallback for direct URL access.

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
…sible

The root route should show the portfolio landing page, not redirect.
Removing beforeLoad redirect and restoring logo link to /.
Also reverts optional search params schema (no longer needed without the redirect).

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
feat(routing): symbol route loaders with validation and error states
# [1.1.0-next.4](v1.1.0-next.3...v1.1.0-next.4) (2026-04-05)

### Bug Fixes

* **routing:** cast redirect params as never to satisfy TS strict router types ([5f82204](5f82204))
* **routing:** link logo directly to /symbol/BTCUSDT ([cf730eb](cf730eb))
* **routing:** remove auto-redirect from / — landing page should be visible ([99bedf4](99bedf4))
* **routing:** remove stale biome-ignore comment on never cast ([58c9f56](58c9f56))
* **routing:** resolve TS errors from 'as never' route cast ([c1b7628](c1b7628))

### Features

* **routing:** symbol route loaders with validation and error states ([014ca0e](014ca0e)), closes [#96](#96) [#98](#98)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
- Export OrderBookState from order-book.tsx for shared typing
- Add useOrderBookViewState(levels) in features/order-book — transforms
  raw Map-based OrderBook into PriceLevel[] view model with cumulative
  totals and percent-width bars; three separate Zustand subscriptions
  avoid infinite re-renders from object-returning selectors
- Add TradesFeed component consuming NormalizedTrade[] — shows time,
  price, qty, side with trading-bid/trading-ask colour coding;
  isBuyerMaker=true → sell (aggressor was seller)
- Replace MOCK_ORDER_BOOK_STATE in trading layout with live
  useOrderBookViewState; show animated skeleton while orderBook is null
- Replace MOCK_TERMINAL_TRADES in DataPanel with live useTrades()
- 18 new tests (use-order-book-data.test.ts + trades-feed.test.tsx)

Closes #96

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>


- Extract LiveIndicatorConnected from RootComponent so __root.tsx
  no longer subscribes to any Zustand store; header re-renders stop
- Add OrderBookPanel + TradesFeedPanel leaf components in -trading-layout;
  TerminalLayout has zero high-freq selectors
- Refactor DataPanel to accept TradesFeedSlot: ReactNode render prop
  so subscription ownership stays in the leaf, not the panel shell

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
…ertyTypes

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
feat(order-book): wire Order Book UI to live WebSocket data
# [1.1.0-next.5](v1.1.0-next.4...v1.1.0-next.5) (2026-04-05)

### Bug Fixes

* **lint:** replace noNonNullAssertion violations in order-book test ([9cd395c](9cd395c))
* **live-indicator:** add undefined to className for exactOptionalPropertyTypes ([34d4f54](34d4f54))

### Features

* **order-book:** wire Order Book UI to live WebSocket data ([0549859](0549859)), closes [#96](#96)

### Performance Improvements

* **root:** scope store subscriptions to leaf components — fix [#104](#104) [#105](#105) ([1404b72](1404b72)), closes [hi#freq](https://github.com/hi/issues/freq)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
…fills

- Add MarketTradesPanel leaf component (owns useTrades() subscription)
- Split Order Book panel: 2/3 order book + 1/3 Market Trades feed
- Add MarketTradesFeed component for NormalizedTrade[] display
- Rename DataPanel Trades tab -> My Trades (shows user simulated fills)

Closes #106

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
…r fills

- Add 'trades' grid panel (key=trades) for live exchange market trades
- MarketTradesFeed + MarketTradesPanel leaf (owns useTrades() subscription)
- DEFAULT_LAYOUTS v12: trades panel sits below order book in bottom row
- redistributeLayout handles new 'trades' column in bottom row alignment
- DataPanel Trades tab renamed to My Trades (user simulated fills)

Closes #106

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
jeziellopes and others added 18 commits April 10, 2026 12:25
feat(order-book): column headers + ARIA table semantics
# [1.1.0-next.22](v1.1.0-next.21...v1.1.0-next.22) (2026-04-10)

### Features

* **order-book:** column headers + semantic table structure ([20633d7](20633d7)), closes [#140](#140) [#144](#144)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
- Add NormalizedCandle interface to domain layer
- Add fetchKlines() to MarketDataSource port + BinanceDataSource impl
- Add klines state, loadKlines action, useKlines selector to market-data store
- Rewrite CandleChart to fetch real klines from Binance REST API
  - Imperative store subscription avoids React re-renders on data updates
  - Race-condition handled by seeding from store state at mount time
- Rewrite PortfolioSummaryWidget to subscribe to portfolio store
  - Removed mock props; only botPnl passed from parent
  - Computes totalBalance/totalPnL/totalPnLPct from USDT balance
- Remove MOCK_CANDLES_BY_INTERVAL and MOCK_PORTFOLIO_SUMMARY from mock-data.ts
- Update market-data.test.ts: add fetchKlines mock + klines reset

Closes #151
Closes #152

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
…rtfolio

feat(chart-portfolio): wire real Binance klines and portfolio store
# [1.1.0-next.23](v1.1.0-next.22...v1.1.0-next.23) (2026-04-10)

### Features

* **chart+portfolio:** wire real Binance klines and portfolio store ([ebd4b32](ebd4b32)), closes [#151](#151) [#152](#152)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
- Add NormalizedKlineUpdate to domain (extends NormalizedCandle + isClosed)
- Add onKlineUpdate() and subscribeKlineStream() to MarketDataSource port
- Add KlineEventSchema to Binance schemas (discriminated union)
- BinanceDataSource: subscribe @kline_<interval> stream after loadKlines;
  reconnects combined WS to include kline sub-stream without disrupting
  depth/trade/ticker streams (wsClient.connect closes old WS silently)
- market-data store: register onKlineUpdate in initMarketData; live ticks
  update last candle (klineIsLiveTick=true); closed candles append to
  ring buffer (max 500, klineIsLiveTick=false); loadKlines calls
  subscribeKlineStream after REST fetch
- CandleChart: uses series.update() for live ticks (no scroll jump) and
  series.setData() + fitContent() for full loads only
- OrderBookRow: depth fill now spans full row via CSS background-image
  gradient on <tr> instead of absolute DepthBar inside first <td>
- Update tests: mock source gets onKlineUpdate/subscribeKlineStream;
  row test checks backgroundImage instead of DepthBar DOM node

Closes #154
Closes #155

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
…-row

fix(chart-order-book): real-time kline stream and full-row depth bar
# [1.1.0-next.24](v1.1.0-next.23...v1.1.0-next.24) (2026-04-10)

### Bug Fixes

* **chart+order-book:** real-time kline stream and full-row depth bar ([45be9af](45be9af)), closes [#154](#154) [#155](#155)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
Replace fitContent() with setVisibleLogicalRange() so the chart opens
anchored to the most recent ~100 candles. This avoids cramming all 500
REST bars into a single tiny viewport on load.

- Added VISIBLE_BARS = 100 constant
- showLatestBars() helper: from=max(0,len-100), to=len+3 (right margin)
- Live tick path (klineIsLiveTick) unchanged — no view jump on every tick
- ResizeObserver fallback uses fitContent() only if no data yet

Closes #157

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
All core features are shipped. Update three documents to reflect reality:

README.md
- Status blurb: "Active development / order book wiring in progress"
  → "P0 + P1 complete"
- What It Does: add OHLCV chart, live ticker, full-row depth bars
- Roadmap table: all six rows now show ✅ Merged with PR links

ROADMAP.md
- P0 table: mark all three features ✅ Merged
- P1 table: mark order entry + portfolio ✅ Merged; add OHLCV row

docs/PRD.md
- In-scope list: replace trading-engine issue link with flow PR links
- All quality-criteria checkboxes flipped from [ ] to [x]
  (TypeScript note clarified: no :any types, a few as casts at Zod boundaries)

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
fix(chart): default to last 100 bars instead of fitContent
# [1.1.0-next.25](v1.1.0-next.24...v1.1.0-next.25) (2026-04-10)

### Bug Fixes

* **chart:** default to last 100 bars instead of fitContent ([8a8ad7a](8a8ad7a)), closes [#157](#157)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
docs: sync README, ROADMAP and PRD to reflect P0+P1 complete
Add Zustand persist middleware so balances and trade history survive
page reloads. Add resetPortfolio() action + confirmation button on
the /portfolio route.

Changes:
- src/stores/portfolio.ts
  - Wrap store with persist() middleware (key: flow:portfolio:v1)
  - partialize: only balances + openOrders + filledOrders persisted
  - merge: clear openOrders on hydration — LocalFillEngine pending
    queue is not restored, so stale limit orders would never fill
  - INITIAL_STATE constant extracted for reuse in reset
  - resetPortfolio() flushes engine pending queue + resets to
    INITIAL_STATE
  - filledOrders capped at MAX_FILLED_ORDERS (500) to bound storage
  - MAX_FILLED_ORDERS = 500 constant

- src/routes/portfolio.tsx
  - Reset button with 2-step inline confirmation (no window.confirm)
  - First click: button turns destructive + shows warning text
  - Second click: calls resetPortfolio() and returns to normal state
  - onBlur resets confirming state if user clicks away

- src/stores/portfolio.test.ts (new file, 5 tests)
  - Initial state assertions
  - resetPortfolio() restores balances + clears orders
  - persist middleware presence verified

Closes #133

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
feat(portfolio): persist state to localStorage with reset button
# [1.1.0-next.26](v1.1.0-next.25...v1.1.0-next.26) (2026-04-10)

### Features

* **portfolio:** persist state to localStorage with reset button ([d092d95](d092d95)), closes [#133](#133)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
Mark the two 🔄 In progress rows as shipped and add two rows for
work completed since the table was last written:

- React composition patterns → ✅ #64
- Route component extraction → ✅ #115
- Typography overhaul (Rajdhani + Noto Sans Mono) → ✅ #122 (new row)
- Tailwind className lint enforcement → ✅ #131 (new row)

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
docs(roadmap): mark all Design System Status items complete
@jeziellopes jeziellopes added the chore Build, CI, dependencies, tooling label Apr 10, 2026
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
flow Ready Ready Preview, Comment Apr 10, 2026 8:22pm

Semantic-release auto-committed chore(release): 1.1.0 directly to main
with CHANGELOG.md and package.json updates. Merging main back into develop
to unblock the develop → main promotion PR (#162).

Resolution:
- CHANGELOG.md: keep develop (all next.x history); semantic-release will
  regenerate the full file for v1.2.0
- package.json: keep develop version 1.1.0-next.26 for the same reason

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
…to flow

- Remove @semantic-release/git: the plugin auto-commits CHANGELOG.md and
  package.json directly to main after every stable release. That commit is
  never in develop, causing conflicts on every subsequent develop → main PR.
  Removing it means semantic-release still tags, publishes GitHub releases
  and generates release notes — just without writing files back to the repo.

- Remove @semantic-release/changelog: only relevant alongside the git plugin
  since nothing commits the generated file without it.

- Rename package name from 'trading-engine' to 'flow' to match the repo.

Signed-off-by: Jeziel Lopes <jeziellopes@gmail.com>
chore(sync): back-merge main v1.1.0 release commit into develop
# [1.2.0-next.1](v1.1.0...v1.2.0-next.1) (2026-04-10)

### Bug Fixes

* **chart+order-book:** real-time kline stream and full-row depth bar ([45be9af](45be9af)), closes [#154](#154) [#155](#155)
* **chart:** default to last 100 bars instead of fitContent ([8a8ad7a](8a8ad7a)), closes [#157](#157)
* **data-panel:** My Trades shows user fills + Activity tab isolation ([1239dac](1239dac)), closes [#97](#97) [#108](#108)
* **ds:** replace bg-ds-gray-800 with bg-muted in Badge; set DataPanel default to trades tab; rename column header to Qty ([acf005f](acf005f)), closes [#138](#138) [#139](#139) [#145](#145)
* **infra:** add order book gap detection and snapshot staleness check ([7a381a5](7a381a5)), closes [#117](#117)
* **landing:** mark all features done; replace inline styles with Tailwind ([074229f](074229f)), closes [#134](#134) [#137](#137)
* **layout:** add sm breakpoint for market trades panel + correct DEFAULT_LAYOUTS v13 ([3815c6a](3815c6a))
* **lint:** replace noNonNullAssertion violations in order-book test ([9cd395c](9cd395c))
* **lint:** resolve Biome import-order and noNonNullAssertion violations ([03d7c04](03d7c04))
* **live-indicator:** add undefined to className for exactOptionalPropertyTypes ([34d4f54](34d4f54))
* **market-data:** align stream subscriptions with Binance spot reference ([7a9d848](7a9d848)), closes [#129](#129)
* **order-book:** align row font size with market trades (text-sm → text-xs, py-px → py-0.5) ([408d228](408d228))
* **order-book:** depth bar fills right-to-left on both bid and ask sides ([2d245ba](2d245ba))
* **order-book:** fix NaN bucketing, correct grouping options, move controls out of drag area ([107d942](107d942))
* **order-book:** remove levels URL param, show 50 rows, clean tab param ([1a2beea](1a2beea))
* **order-book:** replace aria-hidden with role=presentation on SVGs, remove stale Binance reference block ([be2084f](be2084f))
* **order-book:** reverse asks display order so best ask sits nearest spread ([065d02a](065d02a))
* **panel:** conditional cursor-move, title contrast + rich empty states ([2a32aa9](2a32aa9)), closes [#141](#141) [#142](#142) [#143](#143) [#141](#141) [#142](#142) [#143](#143)
* **routing:** cast redirect params as never to satisfy TS strict router types ([5f82204](5f82204))
* **routing:** link logo directly to /symbol/BTCUSDT ([cf730eb](cf730eb))
* **routing:** redirect legacy ?tab=book&levels params to clean URL ([187bad9](187bad9))
* **routing:** remove auto-redirect from / — landing page should be visible ([99bedf4](99bedf4))
* **routing:** remove stale biome-ignore comment on never cast ([58c9f56](58c9f56))
* **routing:** resolve TS errors from 'as never' route cast ([c1b7628](c1b7628))
* **routing:** use location.searchStr in beforeLoad, align typecheck with build ([6ba9652](6ba9652))
* **styles:** update body font-family to Noto Sans Mono (stale Geist Mono ref) ([2eccda9](2eccda9))
* **ui:** add font-mono tabular-nums to Input primitive for consistent number rendering ([17683dc](17683dc))

### Features

* **chart+portfolio:** wire real Binance klines and portfolio store ([ebd4b32](ebd4b32)), closes [#151](#151) [#152](#152)
* **infra:** WebSocket data layer — Binance live market data ([35791df](35791df)), closes [#99](#99)
* **layout:** market trades as separate grid panel, My Trades for user fills ([7b90b0f](7b90b0f)), closes [#106](#106)
* **layout:** market trades under order book, My Trades tab for user fills ([ef19bda](ef19bda)), closes [#106](#106)
* **layout:** trades panel below order book (2/3+1/3), Price/Amount/Time columns ([208dce8](208dce8))
* **order-book:** column headers + semantic table structure ([20633d7](20633d7)), closes [#140](#140) [#144](#144)
* **order-book:** hover highlight + click to set limit price ([65a102b](65a102b)), closes [#126](#126)
* **order-book:** price grouping dropdown + view mode toggle ([#109](#109)) ([0c89887](0c89887))
* **order-book:** wire Order Book UI to live WebSocket data ([0549859](0549859)), closes [#96](#96)
* **order-entry:** simulated order entry with LocalFillEngine ([53ce52a](53ce52a)), closes [#97](#97)
* **portfolio:** persist state to localStorage with reset button ([d092d95](d092d95)), closes [#133](#133)
* **routing:** symbol route loaders with validation and error states ([014ca0e](014ca0e)), closes [#96](#96) [#98](#98)
* **ticker:** wire live price, OHLV, and tick direction from [@mini](https://github.com/mini)Ticker stream; fix portfolio widget ([ac6fd2e](ac6fd2e)), closes [#135](#135) [#136](#136)
* **ui:** add Dropdown primitive; refactor GroupingSelect to use it ([cc3e312](cc3e312))

### Performance Improvements

* **chart:** fix CandleChart blink via PortfolioWidget extraction + stable ref ([d6baa9a](d6baa9a)), closes [#105](#105) [#105](#105)
* **order-book:** prevent CLS micro-stutters on live data updates ([475e041](475e041)), closes [#118](#118)
* **root:** scope store subscriptions to leaf components — fix [#104](#104) [#105](#105) ([1404b72](1404b72)), closes [hi#freq](https://github.com/hi/issues/freq)
* **tab:** fix blank screen and frozen UI on tab return ([e10f617](e10f617)), closes [#113](#113)

Signed-off-by: semantic-release-bot <semantic-release-bot@martynus.net>
chore(release): remove @semantic-release/git plugin + rename package to flow
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Build, CI, dependencies, tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants