Commit Graph

211 Commits

Author SHA1 Message Date
Devin
0a533d5119 fix(web): repair index.css braces damaged by Pattern G dedup script
Commit 14398af's strict-duplicate dedup script ate adjacent newlines/
chars when removing identical rules, leaving:

  - Line 1454: missing `}` to close `@media (max-width: 560px)` block
    that contains .trading-sidebar-{logo,avatar} display:none rule
  - Lines 2632-2635: corrupted "@media ... {media ... {ntral shell..."
    text from overlapping deletions of two adjacent @media blocks
  - Line 2649: `}  .trading-sidebar {` collapsed onto one line without
    a closing brace separator

Symptoms: production Vite build failed with
  [@tailwindcss/vite:generate:build] Missing closing } at media
  (max-width: 560px) — file: /app/web/src/index.css

Fix verified by walking the file with a brace-balance checker:
final depth 0, zero extra-close errors. The audit-css.mjs script
should grow a brace-balance check to prevent this regressing.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 19:30:26 +00:00
Devin
4fc53703c6 feat(backtest): runtime + per-user feature flags (Option C)
Replaces the build-time VITE_BACKTEST_ENABLED gate with a fully runtime
flow: a global Cosmos-backed default (already shipped in the existing
dynamicConfig system) plus a new per-user override layer. An admin can
now enable backtest for specific users without flipping the global
switch — useful for staged rollout and beta testers.

Resolution order: per-user override > global config > env fallback.
Both /api/feature-flags (FE display) and /api/backtest/run (server
guard) consult the same merge logic.

Backend (backend/src/...):
  ~ services/profileRepository.ts
      + TradingUserFeatureFlags interface
      + featureFlags?: TradingUserFeatureFlags on TradingUserProfile
      + setUserFeatureFlags(userId, { backtestEnabled, ... })
      ~ saveCurrentUserProfile() — strip role + featureFlags from input
        so non-admins can't elevate via PATCH /api/me/profile
      ~ mergeTradingUserProfiles() — preserves explicit flag values only
  ~ services/apiServer.ts
      ~ /api/feature-flags merges per-user override into the response
      + /api/admin/users/:userId/feature-flags  (GET — overrides + effective)
      + /api/admin/users/:userId/feature-flags  (PATCH — admin-only writer)
      ~ /api/backtest/run resolves effective flags before guarding
  ~ backtest/index.ts
      + RunBacktestOptions.skipGlobalFeatureFlagCheck
      ~ runBacktest() honors the override (route already gated stricter)

Frontend (web/src/...):
  ~ backtest/flags.ts — isBacktestBuildEnabled() now returns true.
    Kept as a no-op function so existing callers don't break.
  + lib/userFeatureFlagsApi.ts — typed admin client
  + components/admin/UserFeatureFlagsPanel.tsx
      Tri-state picker per flag (Default / On / Off), Look up by user id,
      Save/Reset, shows the merged "effective" value.
  ~ tabs/ConfigTab.tsx — mounts <UserFeatureFlagsPanel /> below the
    existing global Backtest Access Control section.
  ~ layout-fixes.css §27 — styles for the per-user panel.

Tests:
  + testBacktestEngine: skipGlobalFeatureFlagCheck enables per-user
    override semantics. 12/12 regression checks pass.

Security note: featureFlags + role are explicitly stripped from
saveCurrentUserProfile input. Only the admin-only PATCH endpoint can
set per-user overrides.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 19:04:12 +00:00
Devin
4456873ab4 feat(backtest): Alpaca historical data source for equities (Stage C)
Adds BacktestAlpacaSource so saved trade plans for US equities can be
backtested without manual CSV upload. Mirrors the existing Kraken
loader pattern.

Backend:
  + backend/src/backtest/data/alpacaLoader.ts
      loadDatasetFromAlpaca({ symbols, fromTs, toTs, feed, adjustment })
      - Uses the existing @alpacahq/alpaca-trade-api SDK
      - Fetches 15Min bars; normalize.ts aggregates 1h/4h
      - 50-day warm-up lookback so ProEngine has enough EMA/RSI history
      - Throws cleanly with config guidance if ALPACA_API_KEY missing
      - In-memory cache keyed by (symbol, window, feed, adjustment)
  ~ backend/src/backtest/types.ts
      + BacktestAlpacaSource interface
      + 'alpaca' added to BacktestDataSource and BacktestDataSourceType
  ~ backend/src/backtest/data/loadHistoricalData.ts
      Wires 'alpaca' source into the dispatcher

Frontend:
  ~ web/src/backtest/types.ts — adds 'alpaca' to BacktestDataSourceType
  ~ web/src/backtest/components/BacktestConfigurator.tsx
      + 'alpaca' as a SourceType option
      + AUTO_FETCH_SOURCES list — kraken AND alpaca skip the upload-required
        validation
      + 'Alpaca (US equities)' option in the source-picker dropdown
      + Source-picker change handler seeds default IEX/raw Alpaca payload

Tests:
  + testBacktestEngine.ts: new "alpaca data source dispatcher" assertion
    Verifies the type discriminator + error message without hitting
    the network. 11/11 regression checks pass.

Caveats (documented in alpacaLoader inline + ENGINE_READINESS.md §3.4):
  - Free IEX feed has limited symbol coverage (~2016+)
  - SIP feed (paid) needed for full pre-2017 + full-market historical
  - The loader graceful-fails when credentials aren't configured
  - Existing Alpaca live-trading connector unchanged — backtest uses
    its own SDK instance with a different fetch path

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 10:59:06 +00:00
Devin
81b71dc96e feat(web): rolling 'Last N days' presets in backtest picker (Stage E)
Adds a "Recent" preset row to HistoricalPresetPicker with three rolling
windows resolved against today at click time:

  - Last 30 days  — fast feedback for recently saved plans
  - Last 90 days  — captures most recent regime shifts
  - Last 12 months — captures multiple regime cycles

These complement the fixed-date "Historical events" row (COVID etc.)
already shipped in Stage A. Together they answer two distinct user
questions: "how would this plan have played my last 90 days?" (Recent)
vs. "how would this plan have done in the COVID crash?" (Historical).

Internals:
  - Refactored HistoricalEventPreset to use resolveRange() instead of
    static fromDate/toDate strings — lets rolling windows stay accurate
    across days without rebuilding the preset list.
  - HistoricalPresetPicker now accepts both `recentPresets` and
    `historicalPresets` props. Either can be empty/omitted to hide that
    row.

No backend changes — uses existing /api/backtest/run with kraken or
upload sources. Stage E of docs/backtest/ENGINE_READINESS.md §4.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 10:53:08 +00:00
Devin
1a6c0352e3 feat(web): admin-only "Test against history" on /plans cards (Stage A)
Adds a "Test history" action button on each saved-setup card on /plans,
visible only when the authenticated profile has role=admin. Clicking
opens a portaled modal containing the existing BacktestRunnerPanel
pre-loaded with:
  - the plan's TradeProfile.strategy_config (the actual rules + risk
    limits the customer configured)
  - the saved-setup's symbol (overrides profile.symbols when scoped)
  - the profile's allocated_capital as initialCapitalUsd

Also adds a "Historical events" preset row to BacktestConfigurator with
5 pre-validated date ranges (COVID crash, COVID recovery, Russia/Ukraine
2022, 2022 bear market, SVB banking shock). Selecting a preset fills in
the from/to date inputs; manually editing dates clears the active preset
highlight.

This is a customer-experience-neutral change:
  - No production feature flag is flipped (customer non-admins see no
    new UI; existing useBacktestFeatureGate still gates the actual
    backtest API call)
  - No backend changes — reuses existing /api/backtest/run
  - No new strategy code paths

Files:
  + web/src/backtest/components/HistoricalPresetPicker.tsx (new)
  + web/src/backtest/components/BacktestPlanModal.tsx (new, portaled)
  ~ web/src/backtest/components/BacktestConfigurator.tsx (preset wiring)
  ~ web/src/views/SimpleView.tsx (admin button + modal mount)
  ~ web/src/layout-fixes.css (§25 preset chips, §26 modal styles)

Stage A of docs/backtest/ENGINE_READINESS.md §4. Lets admins dogfood
the backtest UX and surface bugs before any customer-facing rollout
(stages B/C/D/F).

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 10:50:59 +00:00
Devin
391b3a9fd3 chore(web): audit-css.mjs — detect true (selector+context+body) duplicates
Extends the script with a strict-duplicate detector that distinguishes
real Pattern G dead code (same selector + same @media context + same
body, where everything but the LAST occurrence in cascade order has no
effect) from descendant-selector counts (which were mostly noise in the
previous report).

The new detector surfaced 29 dead rules in the prior commit (14398af);
it now reports 0 — the cleanup is complete and future regressions will
show up immediately.

Also wires the duplicate-rule data into the --json output for tooling.

Updates docs/ui/UI_AUDIT.md §5 #7 with the consolidation metrics.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 09:51:14 +00:00
Devin
14398af792 refactor(web): consolidate duplicate CSS rules (Pattern G)
The audit-css.mjs script's "rules touching this class" metric over-
reported duplication because descendant selectors got counted alongside
true same-selector duplicates. A more precise scan (selector + @media
context + body identical) found 29 dead-code rules in index.css:

  - 5 .trading-sidebar-logo definitions (the example we already knew
    about; lines 353/1550/2640/2924/3044 — three top-level + two inside
    @media queries with overlapping responsibilities). The canonical
    version lives in layout-fixes.css §22 with all the layout +
    visuals.

  - 24 rules with completely identical (selector + context + body)
    where only the LAST occurrence in cascade order has any effect.
    Earliest copies were pure dead code. Affected: .dashboard-main,
    .dashboard-right-panel, .dashboard-content, .dashboard-shell,
    .trading-sidebar, .trading-sidebar-nav, .trading-sidebar-link,
    .trading-sidebar-avatar, .critical-alert-banner across top-level
    and three @media query contexts. These looked like the result of
    a copy-paste of an entire mobile/tablet @media block.

Also drops 28 !important declarations from layout-fixes.css §22 — those
were only needed to fight the now-deleted index.css duplicates of
.trading-sidebar-logo / .trading-sidebar-brand.

Net impact:
  index.css           3082 -> 2896 lines  (-186, -6%)
  !important total     183 -> 149         (-34,  -19%)
  layout-fixes.css      61 -> 33 !imp     (-28,  -46%)

TypeScript + ESLint both clean. No visual regressions expected — every
deleted rule had an identical surviving copy further down the cascade.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 09:50:14 +00:00
Devin
a48187da83 refactor(web): extract repeated inline-style patterns to classes (UI audit #8)
Per-pattern, per-file analysis found 191 inline-style blocks across the
3 landing-view files (OverviewTab 72, MyStrategiesTab 64, HomeView 55).
155 are unique one-offs already using design tokens (var(--bl-*)) — those
stay inline since converting them to single-use classes would just relocate
code without reducing drift.

This commit extracts the **repeated patterns** (count >= 2 plus structural
container shapes) — 39 occurrences — into either Tailwind utilities or a
new web/src/styles/landing-views.css partial:

  Tailwind replacements:
    textAlign: 'right'                                           → text-right
    marginBottom: '32px' / '24px'                                → mb-8 / mb-6
    fontWeight: 700                                              → font-bold
    flex+justify-between+items-center                            → flex justify-between items-center

  CSS partial (.lv-* classes, all token-driven):
    .lv-card, .lv-card-lg, .lv-icon-tag, .lv-surface, .lv-eyebrow,
    .lv-section-title, .lv-section-sub, .lv-empty-text,
    .lv-divider-row, .lv-meta-faint

Per-file deltas:
    tabs/OverviewTab.tsx       72 -> 53 inline blocks (19 conversions)
    tabs/MyStrategiesTab.tsx   64 -> 55 inline blocks ( 9 conversions)
    views/HomeView.tsx         55 -> 44 inline blocks (11 conversions)

The remaining 152 inline-style blocks are unique one-offs (one usage each)
and already token-driven — extracting them yields no drift reduction.
docs/ui/UI_AUDIT.md §5 #8 updated with this rationale.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 09:39:31 +00:00
Devin
063afdbff6 chore(web): hex-color audit + annotate intentional shadows (UI audit #10)
Extends scripts/audit-css.mjs to also report hardcoded hex colors
outside CSS custom-property defs (`--name: #xxx;`) and outside
`var(--token, #fallback)` token-default fallbacks (which are explicitly
allowed per repo design-system rules).

Initial run reports 4 violations — all intentional pre-cascade body
defaults in :root and html.dark that must be literal hex (no var()) so
the page renders correct colors before the cascade resolves the custom
props. Annotated each with an explanatory comment; values intentionally
mirror --foreground / --background. Future drift surfaces immediately.

UI audit doc §5 #10 updated to reflect the sweep is done and the 4 known
violations are documented.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 09:33:54 +00:00
Devin
63f17bf40e refactor(web): use @bytelyst/ui CardButton primitive (UI audit #9)
Now that @bytelyst/ui@0.1.6 ships <CardButton>, replace the local
`.card-button` className shim (added to layout-fixes.css §25 in the
prior commit) with the real primitive.

Conversions:
  - components/StrategyWizard.tsx — risk style (3 cards) + hours pickers
  - views/SimpleView.tsx — new-buy + manage-holding plan cards
  - tabs/MyStrategiesTab.tsx — diagnostic accordion toggle

Removes layout-fixes.css §25 (.card-button) — no longer needed.
Updates docs/ui/UI_AUDIT.md Pattern A to reflect that the design-system
fix has shipped.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 09:31:46 +00:00
Devin
c10de34a11 chore(web): add CSS audit script for duplicate selectors (UI audit #7)
Adds web/scripts/audit-css.mjs — surfaces classes that appear in many
rules (likely targets of style drift) and per-class !important counts
(specificity-fight indicators). Implements the script suggested by
docs/ui/UI_AUDIT.md §5 #7 / Pattern G.

Run: pnpm --filter @bytelyst/trading-web run audit:css
     (or: cd web && npm run audit:css)

Initial run on src/index.css + src/App.css + src/layout-fixes.css
exposes the top hotspots:
  - .positions-tab     22 rules, 26 !important
  - .trade-plans-page  20 rules, 25 !important
  - .history-tab       17 rules, 22 !important
  - .trading-sidebar-logo  9 rules, 20 !important

These are the targets for the future Pattern G consolidation pass.
The script supports --threshold N and --json for tooling.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 09:24:07 +00:00
Devin
a0fcb65f5d chore(web): add local eslint plugin with UI audit guards (UI audit #6)
Adds a local ESLint plugin (web/eslint-local/) with three custom rules
implementing the preventive guardrails from docs/ui/UI_AUDIT.md §5:

  - bytelyst-trading/truncate-needs-title
      flags JSX elements using Tailwind 'truncate' / 'line-clamp-*' /
      'text-ellipsis' without a paired title= or aria-label= (Pattern E)

  - bytelyst-trading/grid-needs-minmax
      flags gridTemplateColumns string values with bare Nfr tracks not
      wrapped in minmax(0, ...). Catches both literal and template-string
      forms; verifies *every* fr is wrapped, not just one (Pattern F)

  - bytelyst-trading/no-button-with-stacked-children
      flags <Button> from @bytelyst/ui wrapping 2+ block children. The
      Button primitive applies whitespace-nowrap + fixed h-{size} which
      collapses stacked content; recommends native <button class="card-button">
      (Pattern A)

All wired into eslint.config.js as 'warn' (not error) so existing code
isn't broken; new violations show up immediately.

Also fixes the two bare-Nfr grids the new rule caught:
  - components/strategy/CodeStrategyEditor.tsx :270 — repeat(5, 1fr)
  - views/ScreenerView.tsx :142 — '100px 1fr 90px ...'

eslint src/ now reports zero bytelyst-trading/* warnings.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 09:23:05 +00:00
Devin
67c9ecb589 fix(web): convert <Button> picker cards to native <button> (UI audit #5)
The @bytelyst/ui Button primitive applies whitespace-nowrap + fixed
h-{size} which collapses multi-line stacked content (Pattern A in
docs/ui/UI_AUDIT.md). Affected sites use Button as a card-shaped
option/action picker with stacked title + description spans.

Converted to native <button> + new .card-button utility class:
- StrategyWizard:188 — risk style picker (3 cards)
- StrategyWizard:342 — trading hours picker
- SimpleView:1009 — "new short-term buy plan" card
- SimpleView:1028 — "manage existing holding" card
- MyStrategiesTab:153 — diagnostic accordion toggle

Adds layout-fixes.css §25 .card-button — resets button defaults,
preserves focus-visible ring tied to --bl-focus-ring/--bl-accent.

Skipped: ChatControl:543 (FAB) — single-icon child, not affected.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 09:02:54 +00:00
Devin
1807dc0d30 fix(web): grid minmax(0,1fr) + safer header search width (UI audit #2-4)
- index.css :1230 .right-panel-table-* — wrap all four 1fr/1.2fr/2fr columns
  in minmax(0, ...) so cell content can't push the row past container width
- index.css :1620 .trading-header-search — replace `width: min(42vw, 460px)
  !important` with `flex: 1 1 240px; min-width: 0; max-width: 460px`. vw
  units include the sidebar/scrollbar; flex-basis respects the header's
  actual flex container.
- index.css :1895 .home-preview-stats — repeat(3, minmax(0, 1fr))
- 5 inline gridTemplateColumns '1fr 1fr' in MarketplaceTab (x2),
  MembershipTab (x1), MyStrategiesTab (x2) → 'minmax(0, 1fr) minmax(0, 1fr)'

Addresses Pattern F + Pattern H in docs/ui/UI_AUDIT.md.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 08:59:22 +00:00
Devin
1a5172c69a fix(web): add title= to truncated text spans (UI audit #1)
Adds hover-tooltip affordance for ellipsis-truncated values across:
- EntriesTab: symbol, stock_instance_id
- AdminTab: env keys/values, bot config keys/values (refactored second
  block from arrow-fn to block-body to scope displayValue)
- HistoryTab: trade reason
- MarketOpportunities: symbol (both top and bottom lists)
- TradeProfileManager: profile name, profile email

Addresses Pattern E in docs/ui/UI_AUDIT.md.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
EOF
2026-05-10 08:40:32 +00:00
root
343ffb48af fix(web): AI Trading Copilot modal — quick action cards layout
The Quick Actions in the AI Trading Copilot floating modal were broken:
- Always 2 columns regardless of viewport (cards overflowed at narrow widths).
- Used <Button> from primitives which is inline-flex internally; the two
  inline-block <span> children for title and prompt overlapped.
- Prompt was truncated client-side with .slice(0, 55)+'...' instead of
  proper CSS line-clamp, causing inconsistent display.
- No min-width: 0 on grid/card/text so content could push the card past
  the modal width (460px).

Refactored:
- Replaced <Button> with native <button> (cleaner default styling base).
- New CSS classes copilot-quick-action-card, -title, -prompt with explicit
  flex-direction: column so title and description stack reliably.
- Responsive grid: single column below 480px, 2 columns above. The modal
  is 460px wide on desktop and shrinks to viewport-32 on smaller screens,
  so this prevents card overflow on narrow phones.
- Title: single-line truncate with ellipsis, full text exposed via title
  attribute on the button (tooltip + a11y).
- Prompt: -webkit-line-clamp: 2 (no JS slice). Wraps cleanly on long
  prompts. word-break + overflow-wrap as guards.
- Card: min-height 64px so they align in a row without text-length
  jumping. Hover, active, and focus-visible states for keyboard a11y.
- Body container gets bottom padding so the last card is reachable above
  the composer input.

Container changes:
- .copilot-body class added to messages scroll container; bottom padding
  ensures composer doesn't crowd content.
- The modal shell (existing) already uses display:flex; flex-direction:
  column; overflow:hidden so header stays top, body scrolls, composer
  stays bottom — preserved unchanged.

No breaking changes to chat behavior, sendMessage flow, or quick action
prompts.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 08:15:46 +00:00
root
1fa2bcde3b fix(web): alert banner overflow + sidebar logo clipping
Alert banner (top of every page when critical events exist):
- Refactored from a single anchor with inline spans into a structured
  wrapper + inner row with a real CTA link.
- Inner row uses flex-wrap with max-width: 1280px container so the text
  never overflows the viewport.
- Text takes flex: 1 1 auto with min-width: 0 + overflow-wrap: anywhere
  so long messages wrap cleanly. CTA stays shrink-0 so "Go to Admin Panel"
  is always visible.
- On viewports ≤560px the text wraps to its own row above the CTA.
- CTA links directly to /settings?section=Admin%20Panel (the URL the
  Settings router actually consumes), not just /settings.
- Singular/plural ("issue" vs "issues") fixed for n=1.
- Softer styling: card+destructive color-mix instead of bright red,
  no shadow, normal weight, no uppercase.

Sidebar logo / brand block (was clipped):
- Two competing CSS rules (one made it a 44×44 icon-only grid, the
  other a 56px-tall flex row). The grid one was clipping the brand text.
  Now an explicit flex row with min-height: 60px, gap: 12px.
- Icon: shrink-0 22×22.
- Brand wrapper: min-width: 0, two stacked lines with line-height: 1.2/1.3.
- "ByteLyst" and "Trading OS" never clip vertically; they ellipsis-truncate
  if the sidebar is somehow constrained horizontally.
- Below 1279px (tablet sidebar): logo block recenters at 52px tall to fit
  the icon-only narrow sidebar.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 08:06:37 +00:00
root
46a357c0f1 fix(web): trade plans page — clipped chips, action buttons, cramped layout
The Plans page (/plans) had multiple known overflow / clipping bugs:

1. .saved-setup-card { overflow: hidden } clipped the right-side action
   buttons (Edit, Delete) on cards with long content.
2. .saved-setup-meta-grid chips used white-space: nowrap + overflow: hidden
   + text-overflow: ellipsis, which truncated each chip awkwardly instead
   of wrapping. Long Trade ID and Order ID badges blew out the card.
3. .saved-setup-topline used a CSS Grid with auto column for actions, so
   actions could push the title block off-screen at narrow widths.
4. .saved-setup-timeline used 5 fixed-min-width columns that caused
   horizontal overflow on cards <440px wide.
5. The outer two-column grid forced minmax(380px, ...) on the saved-setups
   column which squeezed the form on 1280–1440px screens.
6. The critical alert banner used a loud high-contrast red background and
   uppercase letterspaced text — visually inconsistent with the rest of
   the app.

Fixes applied in web/src/layout-fixes.css (extends existing layout fixes):

- saved-setup-card → overflow visible, never clip children.
- saved-setup-topline → flexbox with flex-wrap, title flexes to 320px
  before actions wrap below to a new row.
- saved-setup-actions → flex-wrap with right-justified items.
- saved-setup-meta-grid chips → real wrapping (white-space: normal,
  overflow visible, max-width 100%, line-height tightened, padding
  expanded slightly for readability).
- Trade-id badges → break-all so long IDs wrap inside their pill.
- saved-setup-timeline → overflow-x: auto so progression scrolls
  inside the card on narrow widths instead of pushing the layout.
- Outer grid → single column below 1440px, two-column 1.15fr/0.85fr
  above. Form gets adequate width on common laptop sizes.
- Alert banner → soft tinted background using card+destructive mix,
  normal weight, no uppercase, integrated with the app shell aesthetic.
- saved-setups-header, asset-row, form sections → flex-wrap + min-width: 0
  so nothing forces horizontal scroll.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 07:36:56 +00:00
root
f463ff64de fix(web): global layout fixes for overlap, clipping, responsive reflow
Adds web/src/layout-fixes.css imported once from main.tsx — surgical
overrides applied with !important so they win against the existing
3000+ line index.css without rewriting it.

Issues fixed:
1. Modals/popovers/dropdowns clipped by .dashboard-main { overflow: hidden }
   → now overflow: visible. Stacking context guard for [role=dialog].
2. Right panel (308px fixed) covers main content on laptop/tablet
   → 260px below 1280px, hidden below 1024px.
3. Tables extending off-screen
   → .dashboard-content table wrapped with display:block + overflow-x:auto
   so they scroll inside their column. Also exposes .scroll-x utility.
4. Header search/indices push each other off-screen
   → flex-wrap on .trading-header, search shrinks to 240–360px range,
   indices wrap with smaller column gap on narrow.
5. Long unbreakable strings (commit SHAs, URLs) escaping containers
   → overflow-wrap: anywhere + word-break: break-word + pre-wrap on <pre>.
6. Sidebar 76px doesn't collapse on mobile
   → 56px below 768px with reduced content padding.

Bumps @bytelyst/devops to ^0.1.3 (responsive panel) in backend + web.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 07:14:50 +00:00
root
bd762d32a9 feat(web): redirect /devops -> /settings?section=DevOps
The DevOps panel lives inside Settings, but typing /devops directly hit
the catch-all NotFoundView. Add a Navigate redirect so the shorthand URL
works.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 06:00:15 +00:00
root
4763a9a9d1 feat(devops): admin-only info, public version, dep checks, role hardening
Backend:
- /api/devops/info now requires admin role (was: any authenticated user).
  Exposes env keys, dep checks, and socket counts — admin-only by design.
- New /api/devops/version (public, no auth) returns build SHA/branch/image
  for ops/CI rollback verification.
- Dep checks: live ping for Cosmos (trading_users) and platform-service.
- Service version read dynamically via readServiceVersion(import.meta.url)
  — no more hardcoded '0.1.0'.
- extra: socketIoConnections + tradingApiUrl for runtime debugging.
- saveCurrentUserProfile no longer accepts client-supplied role —
  prevents drift with platform JWT (which is authoritative).

Web:
- DevOps tab is now admin-only (gated behind isAdmin like Bot Config and
  Admin Panel). Both the section list and content render are guarded.
- Service version baked into bundle via Vite `define` (__WEB_SERVICE_VERSION__)
  read from web/package.json — no more hardcoded VERSION constant.
- Bumps @bytelyst/devops dep to ^0.1.2.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 05:52:48 +00:00
root
74400fda70 feat: migrate web to Gitea registry, add /api/devops/info, fix role drift
Backend:
- Fix role drift: /api/me/profile now returns JWT role authoritatively (was reading
  drifting role from trading_users). PATCH strips client-supplied role.
- Add /api/devops/info endpoint backed by @bytelyst/devops/server.
- Dockerfile: bake BYTELYST_COMMIT_SHA / BYTELYST_BUILT_AT / etc. as build args.

Web:
- Migrate from vendor/ + .pnpmfile.cjs to Gitea npm registry (consistency with backend).
- Replace file: refs in web/package.json with semver ranges resolved from Gitea.
- Drop vendor/bytelyst/* tree and .pnpmfile.cjs.
- Add DevOpsTab in Settings using @bytelyst/devops/ui (tabbed: Build/Runtime/Config/Deps/Raw).
- Vite alias: restrict @bytelyst/* catch-all to single-segment names so subpath
  imports (@bytelyst/devops/ui) resolve via package exports map.
- Bake BYTELYST_* metadata into the bundle as VITE_BYTELYST_* env.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 04:57:09 +00:00
root
15d9eeef12 fix(docker): use shared docker-prep.sh, add UI components, remove pnpmfile
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 01:50:55 +00:00
root
127be5755c revert(docker): revert to vendor approach for trading repo
The base image approach was reverted for notes and clock due to workspace
complexity. The trading repo was still using the base image approach
which is causing build failures. Reverting to the vendor approach
which works reliably for the monorepo structure.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 00:55:54 +00:00
root
a586d3e158 refactor(docker): use shared base images for @bytelyst/* packages
Update Dockerfiles to use bytelyst-common-base-backend and bytelyst-common-base-web
images instead of installing @bytelyst/* packages via vendor directory.

Benefits:
- Smaller final images (~50MB vs ~250MB)
- Faster builds (base image cached)
- Consistent package versions across products
- No need for vendor/ directory maintenance

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 00:27:17 +00:00
93efb14425 chore: add env configuration files 2026-05-09 14:06:28 -07:00
c268567bb6 fix(test): fix JSON generation and disable auto webServer
- Fixed run-e2e.sh to use numeric 0 instead of 'unknown' for test counts
- This resolves JSON parsing error when tests don't run
- Disabled webServer in playwright.config.ts due to Vite -p flag issue
- Tests now require manually starting dev server: cd web && pnpm dev -- --port 3050
- Updated comments in config with instructions for running tests
2026-05-09 13:36:22 -07:00
79f00214a9 test(ui): add comprehensive Playwright E2E test suite
- Created e2e/alert-positioning.spec.ts for critical alerts positioning tests
- Created e2e/assistant-positioning.spec.ts for assistant widget positioning tests
- Created e2e/destructive-actions.spec.ts for destructive actions confirmation tests
- Created e2e/feedback.spec.ts for save/delete/update feedback tests
- Created e2e/page-states.spec.ts for loading/empty/error/success states tests
- Created e2e/form-validation.spec.ts for form validation tests
- Created e2e/keyboard-navigation.spec.ts for keyboard navigation tests
- Created scripts/tests/run-e2e.sh test runner script with health check
- Updated LAUNCH_READY_UI_UX_ROADMAP.md checklist - all items complete
- All testing infrastructure complete (CI integration replaced with local test runner)
2026-05-09 13:28:20 -07:00
8db23bde2d test(ui): add Playwright and Storybook testing infrastructure
- Installed Playwright and Storybook packages
- Created playwright.config.ts with viewport matrix and browser configurations
- Installed Playwright chromium browser
- Created e2e/viewport-matrix.spec.ts for viewport matrix testing
- Created e2e/horizontal-overflow.spec.ts for horizontal overflow testing
- Added test scripts to package.json (test:e2e, test:e2e:ui, test:e2e:viewport, test:e2e:overflow)
- Updated LAUNCH_READY_UI_UX_ROADMAP.md checklist with testing infrastructure status
2026-05-09 13:19:14 -07:00
94ce743bd0 refactor(ui): replace one-off visual language with shared Badge components
- Replace .stat-chip with Badge in PresetMarketplace, BacktestTab, MembershipTab
- Replace .saved-setup-id-chip with Badge in SimpleView
- Replace .screener-sector-chip with Badge in ScreenerView
- Replace .health-pill with Badge in TradeProfileManager
- Remove CSS definitions for one-off classes from index.css
- All components now use shared Badge from product adapter
- Verify: audit:ui (0 findings), audit:ui:strict (0 findings), typecheck, build
2026-05-09 12:56:52 -07:00
8775eab371 test(ui): align markets assertions with shared states 2026-05-09 02:31:02 -07:00
00d8683987 fix(ui): render shared primitives in product shell 2026-05-09 02:29:19 -07:00
ff17c635e3 refactor(ui): standardize history ledger surfaces 2026-05-09 02:22:10 -07:00
d4846b73cc refactor(ui): unify operational alert banners 2026-05-09 02:15:33 -07:00
3951767ab1 refactor(ui): standardize operations table badges 2026-05-09 02:11:52 -07:00
c51544aa29 test(ui): lock responsive shell breakpoints 2026-05-09 02:06:52 -07:00
a65d7261ca test(ui): cover profile rule keyboard toggles 2026-05-09 02:03:10 -07:00
3c525930da fix(ui): improve profile rule keyboard access 2026-05-09 02:00:07 -07:00
cdc0e57ae9 refactor(ui): normalize trade profile controls 2026-05-09 01:58:29 -07:00
1300de98a9 refactor(ui): align wizard and overview controls 2026-05-09 01:55:28 -07:00
f3540c6b4b refactor(ui): normalize admin db sync controls 2026-05-09 01:52:15 -07:00
fd64fecbce refactor(ui): refine positions table controls 2026-05-09 01:50:23 -07:00
bfd7d3bfec refactor(ui): align history filters controls 2026-05-09 01:48:16 -07:00
e1d8ec8a7b refactor(ui): normalize backtest replay controls 2026-05-09 01:46:14 -07:00
3d97e9a0d8 refactor(ui): normalize backtest runner action 2026-05-09 01:43:29 -07:00
979983d3ef refactor(ui): align backtest compare controls 2026-05-09 01:41:43 -07:00
c429488358 refactor(ui): align backtest configurator controls 2026-05-09 01:39:15 -07:00
f8b2107bff refactor(ui): normalize trade plan id chips 2026-05-09 01:36:14 -07:00
217b46e123 refactor(ui): standardize home chart controls 2026-05-09 01:34:41 -07:00
57b8be698d refactor(ui): refine admin console controls 2026-05-09 01:16:06 -07:00