fix: pre-launch UI hardening + KOL reduce-action type, proxy IP relay, settings redesign

Frontend half of the pre-launch audit campaign:

- types/index.ts + kol/KolPageClient.tsx: add missing 'reduce' KolAction
  (backend emits it; frontend lacked the type + color/label maps → undefined
  styling). Adds ACTION_COLOR/actionLabel/postActionLabel entries.
- proxy/[...path]/route.ts: relay real client IP (x-forwarded-for / x-real-ip)
  so the backend rate limiter buckets per-user instead of per-Next-server (BUG-02).
- Settings/BotConfigPanel redesign, paper-mode clarity, copy cleanup.
- Assorted page/display fixes, loading states, Pagination component.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
k
2026-05-29 11:57:43 +08:00
parent b76de36af0
commit d50c05b120
32 changed files with 1003 additions and 224 deletions
+60 -2
View File
@@ -166,8 +166,10 @@ Tokens in `app/[locale]/globals.css`:
## Things that LOOK like bugs but aren't
- **Old code references "/en/btc"** — Macro Vibes was renamed from "BTC
Signal" in v2.0. All routes are now `/en/macro`. If you find a stale
`/en/btc` reference, it's a real bug — fix it (we've found and fixed 3).
Signal" in v2.0. All routes are now `/en/macro`. `app/[locale]/btc/page.tsx`
EXISTS intentionally as a permanent redirect to `/en/macro` — that's fine.
If you find a stale `/en/btc` hardcoded link anywhere else, it's a real
bug — fix it.
- **`isZh = false` in metadata generators** — i18n was shelved pre-launch.
See "Stack quirks" above.
- **Multiple `proxy.ts` patterns** — Next.js 16 split middleware behaviour.
@@ -175,9 +177,65 @@ Tokens in `app/[locale]/globals.css`:
- **`'use client'` directives on many pages** — necessary for client-side
WS / wallet interactions. Don't try to convert without verifying the WS
+ wagmi imports work in server components.
- **`telegram.send_message` accepting `int | str` for chat_id** — the backend
uses string form for the public channel (`"@trumpalpha"`) and integer for
private user chats. Both are valid; no frontend change needed.
- **`x-forwarded-for` is deleted in the proxy** — KNOWN BUG (see below).
Don't "fix" it by just removing the delete; the correct fix is to relay the
real client IP. See Open Known Issues.
---
## Open known issues (frontend)
- ~~**Rate limit bypass via proxy** (FIXED 2026-05-29):~~ `route.ts` no longer
deletes `x-forwarded-for`. It now reads the real client IP from the incoming
`x-forwarded-for` or `x-real-ip` header (set by Vercel/CDN) and sets it on
the upstream request so `slowapi` can distinguish individual clients.
- ~~**`signMessageAsync` in `OpenPositions` polling deps** (MEDIUM, FIXED 2026-05-29):~~
Removed `signMessageAsync` and `isZh` from the `useEffect` dependency array
in `components/positions/OpenPositions.tsx`. Neither is used inside the effect;
including them caused wagmi reference churn to restart the 15s poll timer.
- ~~**Stale types after BUG-08/BUG-14** (FE-0106, FIXED 2026-05-29):~~
- `types/index.ts`: `price_impact.asset` widened from `'BTC' | 'ETH'` to
`string` (BUG-14 now tracks the actually-traded asset which may be
SOL/TRUMP/etc.).
- `lib/useRealtimeData.ts`: `PriceMsg.asset` and `Handlers.onPrice` widened
to `string` (BUG-08 expanded the WS price stream to all ASSET_MAP entries).
- `store/dashboard.ts`: `livePrices` changed from `{ BTC; ETH }` to
`Record<string, number | null>`; `setLivePrice` param widened to `string`.
- `lib/api.ts`: `getPrices` asset param widened to `string`.
- `components/trades/TradeTable.tsx`: hardcoded `ASSETS = ['all','BTC','ETH','SOL']`
replaced by a dynamic `useMemo` that builds the asset list from the actual
trade set — new perps (TRUMP, BNB, etc.) appear in the filter automatically.
- `DashboardClient.tsx` + `TradesPageClient.tsx`: removed `isZh` from
`useEffect` deps (compile-time constant; including it restarted effects
on every render).
- ~~**Interaction/button bugs sweep** (UI-A..G, FIXED 2026-05-29):~~
- **A** `OpenPositions.tsx` close-modal backdrop now dismisses in `'err'`
state too (previously stuck — only `'idle'` dismissed). State is reset on
dismiss so the next open is clean.
- **B** `confirmCloseTrade` distinguishes user-cancelled signature
(`isUserRejection`) from real failure: cancellation closes the modal
silently; real errors stay open in `'err'` state with the message.
- **C** `SystemControl.flipAuto` claims `busy=true` **before** `await
confirmSign(...)`. Rapid double-click on the ON/OFF pill no longer slips
past the guard. The slot is released if the user cancels the sheet.
- **D** `BotConfigPanel` "Rotate" API-key button resets `keyState`/`keyErr`
so a previously-failed save's red error doesn't bleed into the new edit.
- **E** Paper/Live `Switch` clears `subErr` when toggled so a stale
subscribe-error doesn't sit next to the new choice.
- **F** `confirmSign` keeps a module-scope `_activeCancel`; a second call
while a sheet is mounted resolves the first promise with `false` instead
of leaving its caller hanging forever. All 9 call sites verified to
cleanly handle the `false` return (`setBusy(false)` / `setLoadState('idle')`).
- **G** `OpenPositions.toggleGrow` errors now write to a dedicated
`growErr` state with a 4-second auto-clear, instead of squatting in the
panel-header `err` banner shared with the 15-s poll error.
## How to verify changes locally
```bash