diff --git a/docs/design/pages/e2e/fixtures/datasets.js b/docs/design/pages/e2e/fixtures/datasets.js index 848c60b..365e43f 100644 --- a/docs/design/pages/e2e/fixtures/datasets.js +++ b/docs/design/pages/e2e/fixtures/datasets.js @@ -236,8 +236,57 @@ export const MARKET_SIGNAL = { valid_until: new Date(Date.now() + 3600e3).toISOString(), as_of: new Date().toISOString(), }; -// GET /v1/hitl/config — the header's autonomy badge. -export const HITL_CONFIG = { level: 1, threshold_usdt: 100.0, label: "Assistido" }; +// GET /v1/hitl/config — header autonomy badge + the HITL Controls screen. +export const HITL_CONFIG = { + level: 1, current_level: 1, threshold_usdt: 100.0, label: "Assistido", + level_description: "Ordens acima do limite exigem aprovação humana.", + pending_orders_count: 2, human_approved_today: 5, human_rejected_today: 1, + levels: [ + { level: 0, threshold_usdt: 0, description: "Manual — toda ordem exige aprovação." }, + { level: 1, threshold_usdt: 100, description: "Assistido — ordens acima do limite exigem aprovação." }, + { level: 2, threshold_usdt: 500, description: "Semi-autônomo — só ordens grandes exigem aprovação." }, + { level: 3, threshold_usdt: 999999, description: "Autônomo — sem aprovação (confirmação extra)." }, + ], +}; + +// GET /v1/orders — pending queue (HITL) + Orders table. ≥2 pares incl. BTC/USDT +// para os chips de par (N4); confidence (Fix #3) + confidence_breakdown por ordem. +export const ORDERS = [ + { id: "ord_a1", pair: "BTC/USDT", side: "buy", quantity: 0.03, price: 64500, entry: 64500, + stop_loss: 63200, take_profit: 66800, position_size_pct: 2, confidence: 0.82, status: "pending", + strategy: "trend_following", agent_id: "strategy_agent", reason: "Rompimento confirmado por volume.", + created_at: new Date().toISOString(), + confidence_breakdown: [{ key: "trend", score: 0.85 }, { key: "momentum", score: 0.7 }, { key: "volume", score: 0.8 }] }, + { id: "ord_b2", pair: "ETH/USDT", side: "buy", quantity: 0.5, price: 3200, entry: 3200, + stop_loss: 3080, take_profit: 3450, position_size_pct: 2, confidence: 0.71, status: "pending", + strategy: "mean_reversion", agent_id: "strategy_agent", reason: "Reversão no suporte confirmada.", + created_at: new Date().toISOString(), + confidence_breakdown: [{ key: "trend", score: 0.6 }, { key: "momentum", score: 0.75 }, { key: "volume", score: 0.8 }] }, +]; + +// GET /v1/trades — trades fechados (P&L realizado por par, N5). ≥2 símbolos incl. BTC/USDT. +export const TRADES = [ + { order_id: "t1", symbol: "BTC/USDT", side: "buy", entry_price: 61200, exit_price: 64810, quantity: 0.03, fee: 0.5, pnl: 108.30, pnl_pct: 5.9 }, + { order_id: "t2", symbol: "BTC/USDT", side: "buy", entry_price: 65000, exit_price: 63600, quantity: 0.03, fee: 0.5, pnl: -42.10, pnl_pct: -2.1 }, + { order_id: "t3", symbol: "ETH/USDT", side: "buy", entry_price: 3100, exit_price: 3223, quantity: 0.5, fee: 0.3, pnl: 61.50, pnl_pct: 4.0 }, + { order_id: "t4", symbol: "SOL/USDT", side: "buy", entry_price: 150, exit_price: 160.3, quantity: 1.2, fee: 0.2, pnl: 12.38, pnl_pct: 1.5 }, + { order_id: "t5", symbol: "SOL/USDT", side: "buy", entry_price: 148, exit_price: 168.7, quantity: 1.2, fee: 0.2, pnl: 24.90, pnl_pct: 3.0 }, + { order_id: "t6", symbol: "XRP/USDT", side: "buy", entry_price: 0.62, exit_price: 0.60, quantity: 400, fee: 0.1, pnl: -8.20, pnl_pct: -1.3 }, +]; + +// GET /v1/users — exatamente 3 (rbac test 3 afirma tbody tr === 3). +export const USERS = [ + { id: "u_demo", name: "Operador Demo", email: "demo@criptotrade.dev", role: "admin", status: "active", last_login_at: new Date().toISOString(), invite_id: null }, + { id: "u_ana", name: "Ana", email: "ana@criptotrade.dev", role: "operador", status: "active", last_login_at: new Date(Date.now() - 86400e3).toISOString(), invite_id: null }, + { id: "u_novo", name: null, email: "novo@criptotrade.dev", role: "visualizador", status: "pending", last_login_at: null, invite_id: "inv_1" }, +]; + +// GET /v1/roles — a "Matriz de permissões" renderiza de r.permissions. +export const ROLES = [ + { id: "admin", label: "Admin", permissions: ["approve_order", "change_autonomy", "change_risk", "edit_settings", "manage_keys", "view_audit", "manage_users"] }, + { id: "operador", label: "Operador", permissions: ["approve_order", "change_autonomy", "view_audit"] }, + { id: "visualizador", label: "Visualizador", permissions: [] }, +]; // GET /v1/market/{pair}/ticker — the header price (when a single pair is selected). export function ticker(pair) { diff --git a/docs/design/pages/e2e/fixtures/mockApi.js b/docs/design/pages/e2e/fixtures/mockApi.js index 4257887..563ae89 100644 --- a/docs/design/pages/e2e/fixtures/mockApi.js +++ b/docs/design/pages/e2e/fixtures/mockApi.js @@ -15,8 +15,9 @@ import { AGENTS, authMe, candles, deskSummary, EQUITY, HEALTH, HITL_CONFIG, MARKET_INDICATORS, JOURNAL, JOURNAL_METRICS, MARKET_LEVELS, MARKET_PATTERNS, MARKET_REGIME, MARKET_SIGNAL, MARKET_VOLUME_PROFILE, - metrics, ONBOARDING, PAIRS_FLAT, PAIRS_RICH, processEvents, RISK_CIRCUIT_BREAKER, - RISK_CONFIG, RISK_KELLY, RISK_PROTECTIONS, RISK_SKIPS, RISK_SLOTS, SYS_CONFIG, ticker, + metrics, ONBOARDING, ORDERS, PAIRS_FLAT, PAIRS_RICH, processEvents, RISK_CIRCUIT_BREAKER, + RISK_CONFIG, RISK_KELLY, RISK_PROTECTIONS, RISK_SKIPS, RISK_SLOTS, ROLES, SYS_CONFIG, + ticker, TRADES, USERS, } from "./datasets.js"; // Wrap a payload in the API envelope the client's req() unwraps ({ data, meta }). @@ -41,7 +42,10 @@ function baseline({ authMode, role }) { "GET /v1/metrics/equity": () => EQUITY, "GET /v1/onboarding/status": () => ONBOARDING, "GET /v1/desk/summary": () => deskSummary(), - "GET /v1/orders": () => [], // sidebar pending-count poll → empty + "GET /v1/orders": () => ORDERS, // sidebar poll + HITL queue + Ordens + "GET /v1/trades": () => TRADES, // Ordens: P&L realizado por par (N5) + "GET /v1/users": () => USERS, // Usuários & Permissões (exatamente 3) + "GET /v1/roles": () => ROLES, // matriz de permissões // Risco (screen_risk) "GET /v1/risk/protections": () => RISK_PROTECTIONS, "GET /v1/risk/circuit-breaker": () => RISK_CIRCUIT_BREAKER, diff --git a/docs/design/pages/e2e/pair_dimension.spec.js b/docs/design/pages/e2e/pair_dimension.spec.js index 2740df9..74c65d8 100644 --- a/docs/design/pages/e2e/pair_dimension.spec.js +++ b/docs/design/pages/e2e/pair_dimension.spec.js @@ -2,9 +2,10 @@ // N4: HITL ganha mini-contexto do par (preço/regime) + filtro por par na fila. // N5: Ordens ganham o rodapé de P&L realizado por par no modo ∑. import { test, expect } from "@playwright/test"; +import { installMockApi } from "./fixtures/mockApi.js"; test.beforeEach(async ({ page }) => { - await page.addInitScript(() => { window.USE_MOCK_DATA = true; }); + await installMockApi(page, { authMode: "user" }); }); test("N4 — HITL: cada ordem mostra o mini-contexto do par (preço atual)", async ({ page }) => { diff --git a/docs/design/pages/e2e/rbac.spec.js b/docs/design/pages/e2e/rbac.spec.js index 71c422f..98b7b04 100644 --- a/docs/design/pages/e2e/rbac.spec.js +++ b/docs/design/pages/e2e/rbac.spec.js @@ -1,12 +1,11 @@ // A3 RBAC in the console: role-driven visibility (visualizador hides actions, // demo shows them disabled with the discovery tooltip, admin sees everything). +// Cenários de auth/role vêm do fixture (/v1/auth/me), não mais de MOCK_ROLE/MOCK_AUTH. import { test, expect } from "@playwright/test"; +import { installMockApi } from "./fixtures/mockApi.js"; test("visualizador sees no approve/reject and no admin nav", async ({ page }) => { - await page.addInitScript(() => { - window.USE_MOCK_DATA = true; - window.MOCK_ROLE = "visualizador"; - }); + await installMockApi(page, { authMode: "user", role: "visualizador" }); await page.goto("/#hitl"); await expect(page.locator(".page-title")).toContainText("HITL"); await expect(page.getByRole("button", { name: "Aprovar" })).toHaveCount(0); @@ -18,10 +17,7 @@ test("visualizador sees no approve/reject and no admin nav", async ({ page }) => }); test("demo mode shows actions disabled with the discovery tooltip", async ({ page }) => { - await page.addInitScript(() => { - window.USE_MOCK_DATA = true; - window.MOCK_AUTH = "demo"; - }); + await installMockApi(page, { authMode: "demo" }); await page.goto("/#hitl"); const approve = page.getByRole("button", { name: "Aprovar" }).first(); await expect(approve).toBeVisible(); @@ -34,7 +30,7 @@ test("demo mode shows actions disabled with the discovery tooltip", async ({ pag }); test("admin sees the Administração group and the users screen", async ({ page }) => { - await page.addInitScript(() => { window.USE_MOCK_DATA = true; }); + await installMockApi(page, { authMode: "user", role: "admin" }); await page.goto("/"); await page.locator(".nav-item", { hasText: "Usuários & Permissões" }).click(); await expect(page).toHaveURL(/#users$/); @@ -44,10 +40,7 @@ test("admin sees the Administração group and the users screen", async ({ page }); test("operador keeps approve buttons but has no admin nav", async ({ page }) => { - await page.addInitScript(() => { - window.USE_MOCK_DATA = true; - window.MOCK_ROLE = "operador"; - }); + await installMockApi(page, { authMode: "user", role: "operador" }); await page.goto("/#hitl"); await expect(page.getByRole("button", { name: "Aprovar" }).first()).toBeEnabled(); await expect(page.locator(".nav-item", { hasText: "Usuários & Permissões" })) diff --git a/docs/design/pages/e2e/system.spec.js b/docs/design/pages/e2e/system.spec.js index 31b5e15..f62b1f3 100644 --- a/docs/design/pages/e2e/system.spec.js +++ b/docs/design/pages/e2e/system.spec.js @@ -25,6 +25,9 @@ test("route without permission shows 403 with the required permission", async ({ }); test("admin still reaches the users screen directly", async ({ page }) => { + // Users de-mockada (5.4) → serve /v1/users + /v1/roles pelo fixture; USE_MOCK_DATA + // segue só para a auth mock admin (o route-guard). Coexistência transitória. + await installMockApi(page, { authMode: "user", role: "admin" }); await page.addInitScript(() => { window.USE_MOCK_DATA = true; }); await page.goto("/#users"); await expect(page.locator(".page-title")).toContainText("Usuários & Permissões"); diff --git a/docs/design/pages/screen_hitl.jsx b/docs/design/pages/screen_hitl.jsx index 7fae34a..407f272 100644 --- a/docs/design/pages/screen_hitl.jsx +++ b/docs/design/pages/screen_hitl.jsx @@ -97,7 +97,7 @@ function PendingOrderCard({ order, onDecide, highlight = false, ctx = null }) {
)} -