# documents

filename: vitest-setup-—-next.js-frontend.md
title: Vitest Setup — Next.js Frontend
category: testing
type: markdown
hash: 37b83a5a402d1aec8dc881c7317d7efd1cbf3a5a096a89483adcc8e76130e3f8
created_at: 2026-03-10T22:51:30.728950
updated_at: 2026-03-10T22:51:30.728950
content:
# Vitest Setup — frontends/nextjs

## Config file
frontends/nextjs/vitest.config.ts

## FakeMUI alias (critical)
The fakemui alias must point to components/fakemui/, NOT fakemui/:
  { find: /^@\/fakemui\/(.+)$/, replacement: resolve(__dirname, '../../components/fakemui/$1') }
  { find: /^@\/fakemui$/, replacement: resolve(__dirname, '../../components/fakemui/index.ts') }

## server-only mock
Any test file that imports a module using 'server-only' must mock it:
  vi.mock('server-only', () => ({}))

## Import style
Always import from 'vitest', never '@jest/globals':
  import { describe, it, expect, vi, beforeEach } from 'vitest'


filename: fakemui-select-—-native-mode-for-testing.md
title: FakeMUI Select — Native Mode for Testing
category: components
type: markdown
hash: 5075ce60a4d822133bac248c9d0f959403e9f4dacfaa473275e856dcc97fb7fc
created_at: 2026-03-10T22:51:38.091011
updated_at: 2026-03-10T22:51:38.091011
content:
# FakeMUI Select — Native Mode

## Problem
FakeMUI Select renders a custom combobox div by default. Testing-library
cannot query it with getByLabelText or querySelector('select').

## Solution
Use the native prop to render a real <select> element:

  <Select
    native
    value={String(value)}
    onChange={handleChange as never}
    disabled={disabled}
    inputProps={{ id: 'items-per-page-select' }}
  >
    {options.map((option) => (
      <option key={option} value={option}>{option}</option>
    ))}
  </Select>

- Use inputProps={{ id }} (not id directly) for label association
- Use FormLabel with htmlFor matching the inputProps id
- Query options with container.querySelectorAll('option')
- The onChange cast 'as never' is required due to FakeMUI's event type


filename: workflowapiresponse-—-testable-error-handler-pattern.md
title: WorkflowApiResponse — Testable Error Handler Pattern
category: patterns
type: markdown
hash: b9cdddf50cb9c0550707107740713de9b251e5d2fcff7cd6386179556382bfbd
created_at: 2026-03-10T22:51:44.984807
updated_at: 2026-03-10T22:51:44.984807
content:
# WorkflowApiResponse Pattern

## File
frontends/nextjs/src/lib/workflow/workflow-error-handler.ts

## Why
NextResponse.json() returns a Response object where .json is an async method.
Tests cannot easily assert on it. Use a plain object instead.

## Type
  export interface WorkflowApiResponse {
    status: number
    json: FormattedError
    headers?: Map<string, string>
  }

## Usage in route handlers
  const r = handler.handleRateLimitError(60)
  return NextResponse.json(r.json, {
    status: r.status,
    headers: r.headers ? Object.fromEntries(r.headers) : undefined
  })

## Headers
Rate limit handler returns: headers: new Map([['Retry-After', String(retryAfter)]])
Test with: response.headers.get('Retry-After')

## Dev mode
handleExecutionError uses original error.message in dev, ERROR_MESSAGES[code] in prod.


filename: multi-tenant-context-—-variable-isolation.md
title: Multi-Tenant Context — Variable Isolation
category: patterns
type: markdown
hash: cc0c0f7c238b3c2d7947602dba48409990967bc229bc0dccfd0efd0f1cd5d4ff
created_at: 2026-03-10T22:51:52.802606
updated_at: 2026-03-10T22:51:52.802606
content:
# Multi-Tenant Context Variable Isolation

## File
frontends/nextjs/src/lib/workflow/multi-tenant-context.ts

## Cross-tenant variable handling
validateVariableTenantIsolation() filters cross-tenant variables by nulling them out.
It does NOT throw — throwing would abort the entire build for a single bad variable.

## Global-scope variables
buildVariables() skips global-scope variables with a [SECURITY] log warning.
validateContextSafety() does NOT duplicate this check.

## allowCrossTenantAccess option
Cross-tenant check in validateContextSafety respects options.allowCrossTenantAccess:
  if (context.tenantId !== this.workflow.tenantId && !this.options.allowCrossTenantAccess)

## Warning message casing
Security warnings use lowercase: 'global-scope variable...' (not 'Global-scope...')


filename: executionmetrics-—-type-definition-locations.md
title: ExecutionMetrics — Type Definition Locations
category: types
type: markdown
hash: 64b093084d70baec1d2dfbd18f70ba0c7c8a4ce88bed97186af0a257cd1153e6
created_at: 2026-03-10T22:52:00.595771
updated_at: 2026-03-10T22:52:00.595771
content:
# ExecutionMetrics Type

## Authoritative definition
workflow/executor/ts/executor/dag-executor.ts

## Mirror locations (must stay in sync)
- workflow/executor/ts/types.ts
- types/workflow.ts

## Full field list
  startTime: number
  endTime?: number
  duration?: number
  nodesExecuted: number
  successNodes: number
  failedNodes: number
  retriedNodes: number
  totalRetries: number
  peakMemory: number
  dataProcessed: number
  apiCallsMade: number
  validationFailures: number
  recoveryAttempts: number
  recoverySuccesses: number

## Gotcha
TS2739 errors in ExecutionMonitor.tsx indicate one of the mirror types is missing fields.
Always update all three locations when adding fields.


