Artikel/Engineering

Architectural Design: Jett High-Load Testing & Simulation Environment

Technical notes from the Jett team.

This document outlines the architectural blueprints and system design for establishing a robust email simulation and load-testing environment for Jett. The primary goal is to stream synthetic, AI-generated, or template-driven emails (100 to 400 messages per run) to stress-test Jett's synchronization, AI labeling, local storage indices, and virtualized UI rendering layers under heavy inbox loads.


1. Objectives of the Testing Environment

To prepare Jett for scale (targeting the 20,000+ active user milestone in the V4 roadmap), we need to validate and measure performance thresholds under sudden high-concurrency inbox events. The simulation environment will help profile:

  1. Webhook Ingress & Sync Throughput: Verify how the webhook endpoint in route.ts handles 100+ concurrent email sync batches without Vercel Serverless timeouts or Supabase DB pool exhaustion.
  2. AI Labeling Costs & Rate Limits: Profile classification latencies and API rate-limiting behaviors of classifyEmail under load.
  3. Local Store Synchronization Speed: Measure Tauri's IPC speed and SQLite ingestion times in the V4 LocalMailStore.
  4. UI virtualizer Performance (TanStack Virtual): Ensure smooth scrolling (stable 60 FPS) and immediate thread transitions when layout caches are loaded with a dense inbox of 400+ active threads.
  5. Search and Vector Search Speed: Profile SQLite FTS5 matching speed and pgvector semantic query execution limits.

2. Proposed Email Distribution Matrix

To replicate a realistic, high-pressure inbox, we define a target mock distribution:

| Email Category | Applied Badge | Simulated Count | Content Profile / Triggers | | :--- | :--- | :--- | :--- | | Action | action | 60 emails | Requests for signatures, flight reschedules, direct inquiries, scheduling slots, payment deadlines, approval requests. | | Important | important | 80 emails | Server outages, security alerts (new logins, password resets), urgent financial reports, critical client messages. | | Info | info | ~120 emails | Standard transactional documents: DHL tracking, Stripe receipts, flight boarding passes, subscription renewals. | | Offer | offer | ~40 emails | Inbound sponsorship requests, job offers, partnership drafts, SaaS business proposals. | | None | none | ~100 emails | Newsletters, SaaS feature updates, marketing ads, retail coupons, promotional spam. | | Total | | 400 emails | |


3. System Design Options

We evaluate three potential architectural paths to implement this testing suite:

System map

Option 1: Mock API Gateway (End-to-End Simulation)

We build a lightweight mock server (running locally via Bun or a serverless staging route e.g., /api/mock-aurinko/*) that replicates the Aurinko API endpoints:

  • Mock /v1/email/sync/updated returns paginated lists of synthetic emails.
  • Mock webhook notifies /api/aurinko/webhook of new inbox messages.
  • Pros: Tests the *exact* production code path. No modifications required in the core sync client account.ts or database ingestion logic sync-to-db.ts, except changing the API_BASE_URL environment variable.
  • Cons: Higher setup overhead, requiring mock endpoint handlers, request authorization mocks, and validation signatures.

A CLI script or Developer Admin Panel in Settings that creates synthetic JSON email objects matching the EmailMessage interface, with two execution modes:

  • Mode A (Fast UI/Sync Profiling - Bypasses AI Classifiers):

Directly writes the simulated emails into the Supabase database with pre-assigned metadata, subjects, bodies, and target aiLabels (e.g. ['action'], ['important']). This isolates the front-end layout transitions, TanStack virtualizer, and SQLite FTS5 search indexing performance with zero LLM cost.

  • Mode B (End-to-End Webhook & Classification Stress Test):

Fires HTTP mock payload requests to /api/aurinko/webhook directly. This tests: - Next.js serverless route concurrency limits and database pool bottlenecks. - LLM classification reliability, cost, and rate-limiting limits.

  • Pros: Highly customizable, quick setup, zero network mock dependencies, allows selective bypass of the LLM to prevent budget drain.
  • Cons: Bypasses the raw provider layer, but accurately profiles the entire Jett software system.

Option 3: Tauri Local SQLite Injector

A developer command executed directly in the Tauri Rust application that seeds the local client database files directly.

  • Pros: Extremely fast, offline-capable, runs entirely in the Tauri sandbox environment.
  • Cons: Does not test Next.js serverless functions, database webhooks, pgvector storage, or network ingestion latency. Useful primarily for local UI profiling.

4. Implementation Specification (Option 2)

To implement Option 2 (Database Injector & Webhook Emulator), we establish the following components:

4.1. Synthetic Email Generator

We define a simulator service src/lib/testing/email-simulator.ts that generates randomized, contextually rich emails from pre-defined mock templates for each label category.

// src/lib/testing/email-simulator.ts
import { faker } from '@faker-js/faker';
import type { EmailMessage } from '../types';

export interface SimulatedEmailConfig {
  count: number;
  label: 'action' | 'important' | 'info' | 'offer' | 'none';
}

const TEMPLATES = {
  action: [
    { subject: "Urgent Signature Required: {project} Agreement", body: "Hi Sandro, please review and sign the attached {project} contract before the end of the day. We need this to initiate onboarding. Let me know if you have any questions." },
    { subject: "Rescheduling: Sync meeting regarding {topic}", body: "Hi Sandro, I have a conflict during our scheduled time. Could we move the meeting to {date} at {time}? Please reply with your availability." }
  ],
  important: [
    { subject: "[Security Alert] New Login from Unrecognized Device", body: "We detected a new login to your Jett account from a Linux device located in {city}. If this was you, no action is needed. Otherwise, reset your password immediately." },
    { subject: "CRITICAL OUTAGE: Server {server} Database Connection Lost", body: "Alert: The production database server {server} has lost connectivity at {time}. Immediate investigation is required. Response code: 504 Gateway Timeout." }
  ],
  info: [
    { subject: "Your order {orderId} has been shipped", body: "Good news! Your shipment containing your recent order is on its way. Delivery expected via DHL on {date}. Tracking number: {tracking}." },
    { subject: "Stripe Invoice Payment Succeeded for {service}", body: "Your monthly subscription for {service} has been renewed. Amount charged: $49.00 USD. Thank you for your business!" }
  ],
  offer: [
    { subject: "Sponsorship Enquiry: Jett Email Integration", body: "Hello Jett Team, I am reaching out from {company}. We love your product and would love to discuss a sponsorship or partnership deal for our upcoming developer conference." }
  ],
  none: [
    { subject: "Weekly Newsletter: The latest updates in AI", body: "In this week's issue, we cover the launch of new local reasoning models, architectural blueprints for building low-latency Tauri apps, and tech trends." }
  ]
};

export function generateSimulatedEmails(configs: SimulatedEmailConfig[]): EmailMessage[] {
  const messages: EmailMessage[] = [];
  
  for (const config of configs) {
    const templates = TEMPLATES[config.label];
    
    for (let i = 0; i < config.count; i++) {
      const template = templates[Math.floor(Math.random() * templates.length)];
      const threadId = `mock_thread_${faker.string.alphanumeric(10)}`;
      const emailId = `mock_email_${faker.string.alphanumeric(10)}`;
      
      // Interpolate templates with randomized details
      const subject = template.subject
        .replace('{project}', faker.company.projectName())
        .replace('{topic}', faker.company.catchPhrase())
        .replace('{server}', faker.system.commonFileName())
        .replace('{orderId}', faker.string.numeric(8))
        .replace('{service}', faker.company.name())
        .replace('{company}', faker.company.name());
        
      const body = template.body
        .replace('{date}', faker.date.soon().toLocaleDateString())
        .replace('{time}', "14:00 UTC")
        .replace('{city}', faker.location.city())
        .replace('{tracking}', `DHL-${faker.string.numeric(12)}`)
        .replace('{company}', faker.company.name());

      messages.push({
        id: emailId,
        threadId: threadId,
        subject: subject,
        body: body,
        bodySnippet: body.slice(0, 100) + "...",
        from: { name: faker.person.fullName(), address: faker.internet.email() },
        to: [{ name: "Sandro Gantze", address: "sandro@jett.email" }],
        cc: [],
        bcc: [],
        replyTo: [],
        sentAt: faker.date.recent({ days: 3 }).toISOString(),
        receivedAt: new Date().toISOString(),
        createdTime: new Date().toISOString(),
        hasAttachments: false,
        attachments: [],
        sysLabels: ['inbox'],
        keywords: [],
        sysClassifications: [],
        sensitivity: 'normal',
        internetMessageId: `<${emailId}@jett.email>`,
        internetHeaders: [],
        omitted: []
      });
    }
  }
  
  return messages;
}

4.2. Database Seeder Script

We construct a script in scripts/seed-load-test.ts to populate the database directly for fast UI load testing.

// scripts/seed-load-test.ts
import { db } from '~/server/db';
import { generateSimulatedEmails } from '~/lib/testing/email-simulator';
import { syncEmailsToDatabase } from '~/lib/sync-to-db';

async function main() {
  const testAccountEmail = "test-seeder@jett.email";
  console.log(`Starting mock inbox load test generation for: ${testAccountEmail}`);
  
  const account = await db.account.findFirst({
    where: { emailAddress: testAccountEmail }
  });
  
  if (!account) {
    console.error(`Please create a test account with email: ${testAccountEmail} first.`);
    process.exit(1);
  }
  
  const mockPayload = generateSimulatedEmails([
    { label: 'action', count: 60 },
    { label: 'important', count: 80 },
    { label: 'info', count: 120 },
    { label: 'offer', count: 40 },
    { label: 'none', count: 100 }
  ]);
  
  console.log(`Generated ${mockPayload.length} simulated emails. Writing to DB...`);
  
  const startTime = Date.now();
  const syncedEmails = await syncEmailsToDatabase(mockPayload, account.id);
  const duration = Date.now() - startTime;
  
  console.log(`Successfully synced ${syncedEmails.length} emails in ${duration}ms!`);
  
  // Set explicit AI labels to simulate successful categorization
  for (const email of syncedEmails) {
    const originalMock = mockPayload.find(m => m.id === email.id);
    const mockLabel = originalMock ? getMockLabelCategory(originalMock.subject) : 'none';
    await db.email.update({
      where: { id: email.id },
      data: {
        aiLabels: { set: mockLabel !== 'none' ? [mockLabel] : [] }
      }
    });
  }
  
  console.log("Load testing dataset provisioning complete. Open the Tauri app to profile rendering speed.");
}

function getMockLabelCategory(subject: string): string {
  if (subject.includes("Signature") || subject.includes("Rescheduling")) return "action";
  if (subject.includes("Security") || subject.includes("CRITICAL")) return "important";
  if (subject.includes("order") || subject.includes("Invoice")) return "info";
  if (subject.includes("Sponsorship")) return "offer";
  return "none";
}

main().catch(console.error);

5. Verification Plan: Identifying Bottlenecks

Once the test environment is loaded with the 400 simulated emails, we run profiles on the system layers:

1. Webhook Concurrency Limit (Next.js / Supabase)

  • Action: Trigger the simulated emails via simulated webhook loops using curl or a benchmark runner (e.g. k6 or autocannon).
  • Checks:

- Verify that the webhooks respond in < 50ms. - Monitor PostgreSQL connection pools in Supabase to ensure they are not saturated.

2. Client-Side Rendering Speed (Tauri Client)

  • Action: Launch the Tauri client, log into the test account, and scroll the thread list.
  • Checks:

- Verify that the list virtualizer keeps scrolling at 60fps (profile via Chrome DevTools in Tauri). - Verify that opening a thread transitions in < 100ms (zero layouts shift, immediate Zustand hot-cache reading).

3. FTS5 Indexing & Vector Lookup Speed

  • Action: Run broad text searches in the Tauri desktop search bar.
  • Checks:

- Ensure local SQLite FTS5 search queries return results in < 50ms. - Measure pgvector retrieval times in Supabase to ensure matching chunks load under 200ms.


[!NOTE] Setting up a dedicated test email (test-seeder@jett.email) allows dev teams to safely trigger load-testing pipelines without cluttering actual user mailboxes or polluting active production metrics.