Bongo Performance Studio Documentation

Test how fast, stable and healthy your backend is.

This guide explains every screen of the studio: what it does, when to use it, how to read the results, and the technology behind it. Read it top to bottom once, then use the search box (/) to jump to what you need.

Getting Started

Introduction #

What the studio is, who it is for, and what it connects to.

Bongo Performance Studio is a web app that runs on your own computer (by default at http://localhost:3333). It tests any backend that serves an HTTP API, whatever language or framework it is written in, and it can inspect and seed any MongoDB database. See Supported Backends for the details.

It answers questions like: "How many users can our server handle?", "Which API is the slowest?", "Did the last release break any route?", "Are our database queries using indexes?" and "What happens when there are 100,000 records in the database?"

What you can do

Seed test data

Insert realistic dummy documents into any collection, tagged so they can be removed later.

Load & stress test

Normal load, sudden spikes, stepwise stress and rate-limiter checks against any route.

Scan all APIs

One request per route: status, latency, payload size and a ready-to-run cURL command.

Rank slow routes

Same short load test on every route, ranked by p99 latency, throughput and errors.

Audit the database

Index coverage, full collection scans, missing reference indexes and broken references.

Report & compare

Saved run history, side-by-side comparison and a printable executive report with a grade.

Who it is for

  • Backend developers — find slow queries and routes before users do.
  • QA testers — run a regression scan of every API after each change.
  • DevOps — find the breaking point of a server and size it correctly.
  • Team leads — share a clear, graded report with management or clients.

What it connects to

The studio talks to two things, both set per environment on the Settings screen:

ConnectionUsed forExample
Target backend (Base URL)Load tests, benchmark, API scanner, k6, login, online checkhttp://localhost:5000
MongoDB (DB link)Home stats, seeding, purge, inventory, index audit, connected collectionsmongodb://localhost:27017/myapp

Both are optional on their own: without a DB link the testing screens still work, and without a running backend the database screens still work. See Architecture for the full picture.

Supported Backends #

Which kinds of backend code and databases the studio can test.

Any backend that speaks HTTP

The testing screens only send HTTP requests and measure the responses. They never look at your source code, so the language and framework do not matter. If you can call it with curl, the studio can test it.

LanguageExample frameworks
JavaScript / TypeScriptExpress, NestJS, Fastify, Koa, Hapi, Next.js API routes
PythonDjango / Django REST Framework, FastAPI, Flask
PHPLaravel, Symfony, CodeIgniter
Java / KotlinSpring Boot, Quarkus, Micronaut, Ktor
GoGin, Echo, Fiber, net/http
C# / .NETASP.NET Core Web API
RubyRuby on Rails, Sinatra
OthersRust (Actix, Axum), Elixir (Phoenix), serverless functions behind an HTTP endpoint

It does not matter where the backend runs: on your computer, in Docker, on a staging server, in the cloud, or behind Nginx or a load balancer. The studio only needs a reachable http:// or https:// Base URL.

What each feature needs

FeatureWorks withNotes
Load & Spike TestingAny HTTP/HTTPS APISends GET requests only.
Endpoint Benchmark, API ScannerAny HTTP/HTTPS APIGET, POST, PUT, PATCH and DELETE, with a JSON body taken from the API directory.
Cloud Testing (k6)Any HTTP/HTTPS APIThe k6 script can be edited to send any request.
Auth & TokensToken-based loginYour login route must return a token in JSON (or an accessToken cookie). The studio sends it back as Authorization: Bearer <token>.
Home, Seeder, Inventory, Connected Collections, Index Auditor, PurgeMongoDB onlyLocal, Docker or MongoDB Atlas. The backend itself can be written in any language.

What is not covered

  • Other databases. MySQL, PostgreSQL, SQL Server, Redis and others cannot be connected on the database screens. The HTTP testing screens still work for backends that use them.
  • Other ways to log in. The built-in screens only send a Bearer token. API-key headers (such as x-api-key), cookie-only sessions, HTTP Basic auth and OAuth redirect flows are not sent. To use them, set the header in a k6 script.
  • Non-HTTP protocols. WebSockets, gRPC and message queues are not tested by the built-in screens. k6 has its own modules for WebSockets and gRPC that you can use in a custom script, but the dashboard numbers only count HTTP requests.
  • GraphQL errors. A GraphQL API can be tested as a POST route with a body such as {"query":"{ users { id } }"}. Many GraphQL servers return errors with status 200, and the scanner judges only the status code, so those errors still count as passed.

Replace the sample defaults

A few built-in defaults are only examples. Change them to match your backend:

DefaultWhere to change it
Example route list (/api/v1/…)Settings → API route directory: import or type your own routes, and delete the example rows you don't need.
Login route /api/v1/auth/login with an email/password bodyAuth & Tokens → Login Settings.
k6 Target Route listChoose Custom Path in Cloud Testing.
Index Auditor's six preset collectionsFixed. For your own collections, use Connected Collections.
Student / attendance sample seeders (CLI, Seeder Defaults)Ignore them and use the Collections Seeder, which works with any collection.

Quick Start #

From zero to your first test in about five minutes.

Requirements

ItemNeeded forNotes
Node.js 18 or newerEverythingThe project uses ES modules and Express 5.
A running target backendAll testing screensLocal, staging or live URL.
A MongoDB connection stringAll database screensLocal mongod or MongoDB Atlas.
k6 command-line toolCloud Testing onlymacOS: brew install k6. Other systems: see the official k6 install guide.

Steps

  1. Install and start the studio

    Open a terminal in the project folder and run:

    Terminal
    cd bongo_performance_suite
    npm install
    npm start

    Then open http://localhost:3333. To use another port: UI_PORT=4000 npm start.

  2. Point it at your backend and database

    Go to Settings & Environments, choose the Development (DEV) tab and fill in Target Backend Base URL and MongoDB Connection String. Click Test Connection, then Save Settings, then Set as Active Environment.

  3. Check the top bar

    The status pill should turn green and show Online (x ms). The Home cards fill with your database numbers within a few seconds.

  4. Log in once (for protected APIs)

    In Settings, add a Test Login Email and Password (use a dedicated test account). Then open Auth & Tokens and click Log In Now. Every test now sends this token automatically.

  5. Run your first tests

    Start gentle: API Health Scanner → Run Full Health Scan. Then Load & Spike Testing with 20–50 users for 15 seconds.

  6. Review and share

    Open Test History to compare runs, and Executive Report to produce a printable summary.

No .env file is needed. Every setting is entered on the Settings screen and saved in src/config/environments.json. If an old .env exists, its values are copied into Settings once, the first time the server starts.

Interface Tour #

The parts of the screen you will use on every page.

Top bar

ElementWhat it does
Menu (☰)Shows or hides the left sidebar. On phones and tablets the sidebar slides in over the page.
Target fieldThe backend base URL used by Load & Spike Testing and by the online check. It is filled from the active environment; you can edit it for a quick one-off test without changing Settings.
Environment switcherSwitches between DEV, QA and PROD. Each has its own Base URL, DB link, default token and test login.
Status pillThe studio pings the Target every 8 seconds. Any HTTP reply (even 401 or 404) counts as Online and shows the round-trip time. No reply within 3 seconds shows Offline.
Token pillAppears once Auth & Tokens holds a token. Shows its state; click it to open Auth & Tokens.
DocsOpens this documentation in a new tab, so a running test keeps its live view.
Gear iconOpens Settings & Environments.

Sidebar

  • Home — dashboard overview of the database and recent runs.
  • Database — Collections Seeder, Inventory, Index Auditor. (Connected Collections opens from the Seeder page.)
  • Testing — Load & Spike, Endpoint Benchmark, API Scanner, Cloud Testing (k6), Test History, Auth & Tokens.
  • Executive Report and Settings & Environments.

Small badges show live counts, for example the number of documents next to Inventory or saved runs next to Test History.

Live Operation Stream

At the bottom of every studio screen there is a log panel. The server pushes messages to it in real time (seeding progress, test start/finish, errors, k6 output) using Server-Sent Events. Use Clear All to empty it. If something seems stuck, look here first.

You can open a screen directly by adding its name after # in the address bar, for example http://localhost:3333/#loadTest. The Open in Studio buttons in these docs use this.

LinkOpens
#homeHome
#seeder · #relations · #inventory · #auditorDatabase screens
#loadTest · #benchmark · #scanner · #cloud · #history · #authTesting screens
#report · #settingsExecutive Report, Settings

Safety Rules #

The studio works on real servers and real databases. Read this before you click anything big.

Know which database you are connected to. The DB link is used as-is. If your DEV environment points at a cloud database (for example MongoDB Atlas), seeding and purging change that cloud database.

The rules

  1. Seeding writes real documents. Every dummy document is tagged with isPerformanceTestData: true so it can be removed later. See Dummy Data & Purge.
  2. Purge deletes real documents — only those that match the test-data rules, but it deletes them for good. There is no undo.
  3. Do not seed or load-test PROD unless it is planned and agreed. The Settings screen shows a warning banner when PROD is selected.
  4. Load tests create real traffic. On a shared server, other users will feel it. Start small and increase step by step.
  5. Rate limiters can block you. Many backends limit requests per IP, for example 500 requests per 5 minutes overall and only a few login attempts per 5 minutes. After a big test, your IP may get HTTP 429 until the limit window resets. Find out your backend's limits before testing.
  6. Write routes are sent for real. POST / PUT / DELETE routes in the API directory create, change or delete records when the scanner or benchmark runs them.
  7. Use a dedicated test account for Test Login, never a real admin or customer account.
  8. Settings contain secrets. src/config/environments.json stores DB links, tokens and the test password in plain text. Do not commit or share it.

Safest setup: run the backend locally against a local or scratch MongoDB, test there, purge when finished.

Database

Home Dashboard #

A live overview of the active database, the backend status and your latest runs.

Sidebar → Home Read-only (except Purge All) Open in Studio

Quick actions

The buttons next to the greeting jump straight to API Scanner, Executive Report and Cloud Testing (k6).

The eight KPI cards

CardWhat it means
Total RecordsDocuments across all collections. The line below shows how many collections exist.
Total DiskSpace the database uses on disk: document storage + indexes.
Doc StorageOn-disk (compressed) size of the documents only.
Index SizeOn-disk size of all indexes, plus how many indexes exist.
Logical DataUncompressed size of all documents, plus the average document size.
Test DataHow many documents are dummy test data, and their share of the database.
Env & PingActive environment and the latest round-trip time to the backend.
Test PurgePurge All opens a confirmation, then deletes every tagged dummy document.

Storage cards

  • Document Storage and Index Storage rings show each part's share of total disk. Detail opens Inventory or the Index Auditor.
  • Storage Engine shows the total footprint, the uncompressed data size and the compression ratio (uncompressed data ÷ document storage).

Why can the ratio be below 1× (for example 0.1×)? MongoDB's WiredTiger engine keeps every collection and index in its own file with a minimum size, and keeps freed space after deletes for reuse. On a small or freshly purged database those files are larger than the data itself. On large databases the ratio is usually above 1× because WiredTiger compresses documents.

Insights row

  • Health Overview — quick checks: backend online and ping (warns above 1.5 s), latest API scan score, latest saved load test, reference indexes and broken references (from Connected Collections). Click a row to open the related screen.
  • Recent Test Runs — the newest saved runs from reports/. Open Test History shows all of them.
  • Largest Collections — bar chart of the biggest collections by Documents or Disk Size.

Home uses only data that is already available. It never starts a scan or test on its own. The numbers refresh every 8 seconds.

Collections Seeder #

Fill any collection with realistic dummy documents to see how the backend behaves with big data.

Database → Collections Seeder Writes to the database Open in Studio

Option 1: Seed all collections (1-click)

The Universal Master Seeder card adds the same number of documents to every collection in the active database (system collections and sessions are skipped).

VolumeDocuments per collectionGood for
Small200A quick check that seeding works
Medium (default)1,000Everyday testing
High Stress2,500Pagination and index tests
Extreme Stress5,000Large-dataset simulation

With 100 collections, Medium adds about 100,000 documents. Progress appears in the Live Operation Stream.

Option 2: Seed one collection

  1. Find the collection

    Use the filter box, or sort by documents, disk space, storage, index size, data size, name or "Most Dummy".

  2. Choose a count

    Click a preset (100, 500, 1k, 5k) or type your own number on the collection card.

  3. Seed

    Click the seed button on the card. Refresh reloads the list and counts.

How the dummy documents are made

The seeder does not need your schema. It reads one existing document from the collection and builds new documents with the same field names and types:

Field in the templateValue in the dummy document
ObjectId (or 24-character id)A new random ObjectId
Name contains emailperf_…@bongo-test.local
Name contains nameA fake full name with "(Test N)"
phone / mobileA Bangladeshi-style number +8801…
passA fixed dummy hash (nobody can log in with it)
status, role, gender, priorityA random value from a short list
code, id, number, key, slug…PERF_XXXXXX_… (unique)
title / desc / message / textA product name or a lorem sentence
Number50–5,000 for price/amount/fee, 10–500 for count/limit, else 1–10,000
Boolean / DateRandom true/false · a date in the last 30 days
Array / nested objectEmpty [] / {}

Every document also gets isPerformanceTestData: true, createdAt and updatedAt. An empty collection (no template) gets simple documents with name, code, status and description. Documents are inserted in batches of 1,000; duplicate-key collisions are skipped and logged.

Good for volume, not for app logic. Dummy documents are valid for MongoDB but may not follow your app's rules (allowed values, required links between records). Use them to test speed, indexes and pagination, not business flows.

Their reference fields point to random ids that do not exist, so they show up as broken references in Connected Collections until you purge.

Connected Collections #

A map of how collections reference each other, with missing indexes and broken references highlighted.

Collections Seeder → Connected Collections Read-only Open in Studio

How it works

The newest 20 documents of each collection are sampled. Any ObjectId (or 24-character id string) whose value exists as an _id in another collection becomes an arrow A → B: "documents in A store the id of a document in B". Results are cached for 5 minutes; Re-scan builds the map again. Nothing is written to the database.

Reading the map

You seeMeaning
Solid arrowA reference between two collections. Click a collection to highlight what it References and what it is Referenced by.
Dashed arrowNo index: the reference field has no index that starts with it. Lookups on that field scan the whole collection.
Red arrowBroken refs: some documents point to records that no longer exist.
CountersCollections, connected, relationships, unindexed and broken totals.

Tools on this screen

  • Find a collection — search and focus a node. Fit to Screen resets the view.
  • Check Broken References — counts documents whose reference points to a missing record (read-only $lookup).
  • Collection Details — click a node to see which fields link it to other collections.
  • Index & Integrity Findings — lists unindexed reference fields with a ready createIndex command, and broken-reference counts.
  • Not Connected — collections with no detected links in either direction.

A reference field that is empty in all 20 sampled documents can be missed. The map shows what the data says, not what the code intends.

Collections Inventory #

One table with the size of every collection, split into dummy and real data.

Database → Inventory Read-only Open in Studio

Summary tiles at the top show total collections, documents, disk space, document storage, index size and uncompressed data. The table below has one row per collection:

ColumnMeaning
DocumentsNumber of documents in the collection.
Total Disk SpaceDocument storage + index size on disk.
Doc Storage / Index SizeThe two parts of the disk space.
Data Size (Avg)Uncompressed size, with the average document size.
Dummy Test / Real DataHow many documents are tagged test data vs everything else.
DistributionA bar showing the dummy vs real share.

Use the search box to filter by name and Refresh after seeding or purging.

Index Auditor #

Checks whether typical queries use an index or scan the whole collection.

Database → Index Auditor Read-only Open in Studio

What "Run Live DB Audit" does

The auditor works on a fixed preset of six collections. For each one it lists every index (name, keys, unique) and runs one typical query with MongoDB's explain("executionStats"):

Preset collectionField the test query filters on
usersemail (exact match)
studentsstudentId (exact match)
teachersteacherId (exact match)
attendancesdate (last 30 days)
feeinvoicesstatus (exact match)
academicclassesclassCode (exact match)

Reading the result

  • IXSCAN (index scan) — good. MongoDB jumped straight to the matching entries.
  • COLLSCAN (collection scan) — slow. MongoDB read every document because no index matched.
  • Docs examined vs keys examined — many documents examined for few results means a missing or poor index.
  • Health score — the share of the six collections whose query did not do a COLLSCAN.

Below the results you get best-practice recommendations (connection pool size and compound indexes for the preset collections) with copy-ready code.

The six collection names are fixed. If your database does not have them, they show 0 documents and are not explained. To find missing indexes in any database, use Connected Collections: it lists every reference field without an index, with a ready createIndex command.

Testing

Load & Spike Testing #

Send many requests to one route at the same time and measure speed and failures.

Testing → Load & Spike Testing Sends real traffic Load & spike runs saved Open in Studio

The four scenarios

ScenarioWhat happensUse it to
Standard Load TestThe chosen number of users send requests non-stop for the chosen time.Measure normal peak performance.
Sudden Traffic SpikeAll users start at once, with a 10-second timeout per request. Watch the drop rate (5xx + timeouts).See if the server survives a burst, e.g. result publishing.
Breaking Point StressFour stages at 20%, 50%, 80% and 100% of the users; each stage gets a quarter of the duration (at least 3 s). Each stage's numbers appear in the Live Operation Stream; the scorecard shows the overall result with the worst p95.Find where latency and errors start to climb.
Rate Limiter AuditIgnores the sliders and the token. Sends 550 GET requests with 25 parallel workers and counts HTTP 200 vs 429, plus the request number of the first 429. The counts are printed in the terminal where npm start runs; the scorecard is not filled for this scenario.Confirm that express-rate-limit blocks abuse.

How to run a test

  1. Pick a scenario

    Click one of the four scenario cards.

  2. Set users and duration

    Concurrent Virtual Users: 5–500. Duration: 5–60 seconds. Start with 20–50 users.

  3. Choose the route

    Pick from Select API Route to Hit (filled from the API directory in Settings) or choose Custom Endpoint Path. You can edit the path and add query parameters, e.g. /api/v1/users?page=1&limit=20.

  4. Add a token if the route is protected

    The Bearer Token field is filled automatically from Auth & Tokens. Without a token, protected routes answer 401 and the test measures only the rejection.

  5. Launch

    Click Launch Load Test. The scorecard shows the result when the run finishes.

Results scorecard

NumberMeaning
Requests / SecAverage requests the server completed per second. Higher is better.
Avg LatencyAverage time from request to response.
p95 Latency95% of requests were faster than this. The best single number for "how slow does it feel".
Errors / Drop RateServer errors (5xx) plus timeouts. Should be 0.

GET only. This screen always sends GET, even if the route in the directory is POST. Use the API Scanner or Endpoint Benchmark for other methods.

Saved runs: Standard Load and Spike results are saved to reports/ and appear in Test History. Stress and Rate Limiter results are shown on screen and in the log only.

The Rate Limiter Audit is meant to trigger the limiter. Afterwards your IP can receive 429 responses until the limiter window resets (often several minutes), which also affects other tests. 550 requests are enough to pass a limit of 500; if your backend allows more, the audit shows no 429.

Endpoint Benchmark #

Run the same short load test on every route and rank them to find the slow ones.

Testing → Endpoint Benchmark Sends real traffic Saved to Test History Open in Studio

Settings

FieldMeaning
Target Base URLTaken from the top bar unless you edit it here.
Users per route1–100 concurrent users for each route.
Seconds per route3, 5, 10 or 15 seconds per route.
RoutesHow many routes from the API directory will run.
Include write routesOff by default: only GET routes run. When on, POST / PUT / DELETE routes run too, with their saved body.

Routes run one after another, so the total time is about routes × seconds per route (40 routes × 5 s ≈ 3.5 minutes). Duplicate method + path pairs run once. The token from Auth & Tokens is used automatically. Stop ends the run after the current route; finished routes are still saved.

Results

Routes are ranked by p99 latency (slowest first). Each row shows requests/sec, average, p50 / p90 / p99 and max latency, errors (network errors + timeouts), non-2xx responses and the 2xx / 4xx / 5xx split. Every run is saved as reports/endpoint_benchmark_*.json; you can reopen and compare runs in Test History.

Include write routes sends real POST / PUT / DELETE requests many times per second: POST creates records, PUT changes them and DELETE removes them. Only use it against a test database.

API Health Scanner #

One request to every route: is it up, what status does it return, how fast is it?

Testing → API Scanner One request per route Saved to Test History Open in Studio

How to run a scan

  1. Check the target and token

    Target Base URL follows the active environment. The Bearer Token is filled from Auth & Tokens.

  2. Choose speed

    Concurrency: 1, 3, 5 (recommended) or 10 parallel workers. Timeout: 3, 6 or 10 seconds per request.

  3. Run Full Health Scan

    Every route in the API directory is called once, with its method and saved body. Stop Scan cancels it.

Reading the results

ItemMeaning
Health ScorePassed routes ÷ scanned routes. A route passes when it returns HTTP 2xx or 3xx.
Endpoints ScannedTotal, passed and failed.
Avg LatencyAverage response time, with min and max.
Status BreakdownCount of 2xx, 4xx and 5xx, and the failure rate.
FiltersAll, Passing, Failing, and Slow (> 300 ms). Search by path or name.
ReproductionA ready cURL command for each route, so you can repeat the exact request in a terminal.

Special status values

  • 0 · Connection Refused — nothing is listening at the Base URL. Is the backend running?
  • 408 · Request Timeout — no answer within the timeout.
  • 500 · Network Error — another network problem (DNS, TLS…). Check the message; this is not necessarily a real server 500.
  • 401 / 403 — usually a missing or expired token. Log in again in Auth & Tokens.

Export JSON downloads the full result. Each scan is saved to Test History with the token replaced by <token>, and the latest scan feeds the Executive Report.

Cloud Testing (k6) #

Run Grafana k6 load-test scripts from the studio, with Grafana-style panels and a Prometheus metrics endpoint.

Testing → Cloud Testing Sends real traffic Saved to Test History Open in Studio

k6 must be installed on the computer that runs the studio server (brew install k6 on macOS). The test runs locally with k6 run; "Cloud" refers to the k6 / Grafana tooling, nothing is uploaded to Grafana Cloud.

How to run a k6 test

  1. Pick a preset

    The preset sets the number of virtual users (VUs) and the duration (table below).

  2. Pick the target route

    Choose a route or Custom Path. The host comes from the top-bar Target field.

  3. Check the token

    The Authorization Bearer Token is filled from Auth & Tokens and written into the script.

  4. Review the script

    The editor shows the exact k6 JavaScript that will run. You can edit it.

  5. Run k6 Cloud Test

    The k6 Engine Log tab shows k6's output. Abort Test stops it.

Presets

PresetVUsDurationPurpose
Smoke Test510 sSanity check that the route answers correctly.
Standard Load Test10030 sTypical peak traffic.
Traffic Spike Test40020 sSudden burst.
Stress & Breaking Point50040 sMaximum capacity.
Soak / Endurance5060 sSteady load to reveal memory or connection leaks.
Multi-Step API User Flow10030 sSeveral routes in one user journey.

What actually runs

The script in the editor is exactly what k6 runs. The studio writes a simple script for you: the chosen VUs for the whole duration, one GET request to the route, a check that the status is 200, and a threshold of p95 < 500 ms.

  • Changing the preset, route or token, or clicking Reset Script, rewrites the script and replaces your edits. Make manual edits last.
  • Moving the VUs or Duration slider does not change the script by itself. Click Reset Script afterwards to apply the new values.
  • To run the built-in staged version of a preset (ramp up → hold → ramp down, and the multi-step flow), clear the editor completely before clicking Run. The server then uses its own template for that preset.
  • Export .js downloads the script so you can run k6 run test.js yourself or in CI.

Dashboard panels

The six KPI cards (VUs, throughput, p95, p99, error rate, checks passed) come from k6's own end-of-test summary, so they are exact. An error rate under 1% is shown as SLA Healthy.

The four charts are an approximation. k6's summary has no per-second data, so the charts are drawn after the run as a smooth curve shaped from the final p95 and requests/sec. Read them as an illustration, not as measurements. Likewise, failed requests are split into 4xx / 5xx by an estimate; use the API Scanner for exact status codes.

Prometheus and PromQL

  • Raw /metrics Stream shows the studio's own endpoint http://localhost:3333/metrics in Prometheus text format: request counts by status, latency quantiles from the last k6 run, current/peak VUs, and the studio process's CPU, heap memory and uptime. A real Prometheus server can scrape it.
  • PromQL Explorer is a simplified lookup, not a full PromQL engine. It recognises the words http_requests_total, duration / latency, vus, cpu and heap / mem and returns the matching current values. Functions such as rate() are not calculated.

Each run is saved to Test History, and the latest run feeds the Executive Report.

Test History & Compare #

Every saved run in one table, with side-by-side comparison to spot regressions.

Testing → Test History Reads the reports/ folder Open in Studio

What is saved

KindComes fromFile name
Load & SpikeStandard Load and Spike tests (and CLI smoke/load/spike)standard_load_test_*.json, traffic_spike_test_*.json
Endpoint BenchmarkEndpoint Benchmarkendpoint_benchmark_*.json
k6 CloudCloud Testingk6_*.json
API ScanAPI Health Scannerapi_health_scan_*.json

Using the table

  • Filter by kind or search by route; Refresh reloads the folder.
  • Columns: run, when, setup, requests/sec, average, p99, problems, status and actions.
  • View opens the full details of a run. Delete removes the file from reports/ (it asks first).

Comparing two runs

  1. Tick two runs

    They must be the same kind: two load tests (k6 runs count as load tests here), two benchmarks or two API scans.

  2. Click Compare

    A is the older run, B the newer one. You see the change in each number; for benchmarks per route, for scans which routes changed status.

Run the same test with the same settings before and after a change. Any difference is then caused by the change, not by different test settings.

Auth & Tokens #

Log in once and every test uses the same token automatically.

Testing → Auth & Tokens Calls the login route Open in Studio

Login settings (per environment)

FieldMeaning
Login endpointYour backend's login route. The default /api/v1/auth/login is only an example.
MethodPOST, PUT or GET.
Request body (JSON)May use {{TEST_ADMIN_EMAIL}} and {{TEST_ADMIN_PASSWORD}}. The server replaces them with the Test Login Email / Password from Settings. Only these two placeholders are allowed.
Token locationauto finds accessToken, access_token, token, jwt or idToken in the response (or an accessToken cookie). Or give a path such as data.accessToken.
Default login body
{
  "email": "{{TEST_ADMIN_EMAIL}}",
  "password": "{{TEST_ADMIN_PASSWORD}}"
}

The current token

  • Log In Now calls the login route and keeps the token in the studio server's memory for the active environment, with its expiry time (read from the JWT).
  • You can copy it, Clear Token, or Paste a token instead → Use This Token.
  • The token is lost when the studio server restarts; log in again.

Where the token is used

The token fields of Load & Spike Testing, API Health Scanner and Cloud Testing (k6) are filled automatically, unless you typed a different token there. Endpoint Benchmark uses it directly. Before a test, the studio logs in again only if the token expires within one minute.

Login routes are often rate-limited strictly, for example 5 attempts per 5 minutes per IP. Do not click Log In Now repeatedly; if you get HTTP 429, wait until the limit resets.

Reports & Setup

Executive Report #

A one-page, graded summary you can print, save as PDF or paste as Markdown.

Sidebar → Executive Report Read-only Open in Studio

Where the numbers come from

Report partSource
Database architectureLive database stats (disk, storage, indexes, records, compression).
Load test scorecardThe latest k6 run from Cloud Testing.
API health scorecardThe latest API Health Scan.

Run a k6 test and an API scan first. Load & Spike (autocannon) results are not used. The latest k6 run and scan are kept in server memory, so after a studio restart run them again.

Without them the load and API parts are empty, and the grade can look better than it really is.

How the grade is calculated

The score starts at 100 and loses points:

  • error rate × 10 (for example 2% errors = −20)
  • p95 latency above 300 ms: −5 · above 500 ms: −15 · above 1,000 ms: −25
  • (100 − API health score) × 0.5
GradeRuleVerdict
A+Score ≥ 95, 0% errors and p95 < 300 msProduction ready
AScore ≥ 85Production capable
BScore ≥ 70Acceptable for staging
CScore ≥ 55Needs optimisation
FBelow 55Critical remediation required

Recommendations are added by rule: high error rate, p95 above 500 ms, more than 5,000 records (pagination advice), plus two general tips (caching and CI regression tests).

Sharing

  • Generate Fresh Report — builds the report from the current data.
  • Copy Markdown — paste into GitHub, Slack, Notion or an email.
  • Print / Save as PDF — the print layout hides the sidebar and controls; choose "Save as PDF" in the print dialog.

Settings & Environments #

Targets, database links, test login, seeder defaults and the API route directory.

Sidebar → Settings & Environments Saved to environments.json Open in Studio

Environments (DEV, QA, PROD)

FieldMeaning
Target Backend Base URLWhere load tests and API calls go, e.g. http://localhost:5000.
Environment Display LabelFriendly name shown in the top-bar switcher.
MongoDB Connection StringUsed for stats, seeding, purge, inventory and audits.
Default Bearer TokenOptional fallback token for protected routes.
Test Login Email / PasswordUsed by Auth & Tokens as {{TEST_ADMIN_EMAIL}} / {{TEST_ADMIN_PASSWORD}}.

Test Connection pings the Base URL and opens a short test connection to MongoDB (reports the number of collections). Save Settings stores the tab; Set as Active Environment makes it the one every screen uses.

Seeder defaults

Insert Batch Size, Default Student Count and Default Attendance Count are used by the built-in student/attendance sample seeders and the command-line tools. The Collections Seeder does not use them.

API route directory

The list of routes used by Load & Spike Testing, Endpoint Benchmark and the API Scanner. Add routes in two ways:

Option 1 — upload files

Drag & drop or browse: Excel (.xlsx, .xls), .csv, .json or .txt. Several files at once; every sheet is read. Download the Excel, CSV or JSON template to start.

ColumnRequiredExample / notes
PathYes/api/v1/users — full URLs and ?query are fine
MethodNoGET, POST, PUT or DELETE (empty = GET)
NameNoLabel shown in the route dropdowns
CategoryNoGroups routes (empty = the sheet name)
BodyNoJSON sent with POST / PUT, e.g. {"name":"Test"}

The first row must be the column headers. Rows already in the list (same method + path) are skipped.

Option 2 — type them in

One path per line, pick the method and an optional category, add a JSON body for POST / PUT, then Add Routes. The table below lists all routes; filter, delete single routes, or Reset to Default Routes.

How settings are saved

  • On the server in src/config/environments.json.
  • A copy is also saved in this browser (localStorage key bongoStudio.settings). When the studio loads and the server's settings differ, the browser copy is pushed back to the server — the browser copy wins.

If you edit environments.json by hand and your change disappears after a reload, the browser copy overwrote it. Save the change through the Settings screen instead, or clear this site's data in the browser.

Guides

Recommended Workflows #

Step-by-step recipes for the most common jobs.

Before every release (regression check)

  1. Log in

    Auth & Tokens → Log In Now.

  2. Scan

    API Health Scanner → Run Full Health Scan. Target: 100% health.

  3. Compare

    Test History → tick this scan and the previous one → Compare. Investigate any route that changed from passing to failing.

  4. Load

    Cloud Testing → Standard Load preset on the busiest route.

  5. Report

    Executive Report → Generate → Print / Save as PDF.

Find and fix slow endpoints

  1. Benchmark

    Endpoint Benchmark, GET only, 10 users, 5 seconds per route.

  2. Pick the worst

    Look at the top of the list (highest p99).

  3. Check the database

    Index Auditor for COLLSCANs; Connected Collections for unindexed reference fields (copy the createIndex command).

  4. Fix and re-run

    Add the index or pagination, run the same benchmark, compare in Test History.

Prepare for a traffic peak (launch, sale, big announcement)

  1. Seed realistic volume

    Collections Seeder → bring key collections to the size you expect.

  2. Normal load

    Load & Spike → Standard Load at your expected number of users.

  3. Spike

    Sudden Traffic Spike at 3–5× that number. Drop rate should stay near 0%.

  4. Find the limit

    Breaking Point Stress. Note the stage where p95 passes 1 s or errors appear: that is your capacity.

  5. Clean up

    Home → Purge All.

Monthly database health check

  1. Inventory

    Which collections grow fastest? Is index size reasonable?

  2. Index Auditor

    Any COLLSCAN?

  3. Connected Collections

    Re-scan, then Check Broken References. Fix unindexed and broken references.

Reading the Metrics #

What each number means and what counts as good.

Good, watch, bad

These are the thresholds the studio itself uses for grades and warnings.

p95 latency

GoodUnder 300 ms
Watch300 ms – 1 s
BadOver 1 s

Error rate

GoodUnder 1% (SLA healthy)
Watch1% – 5%
BadOver 5% (over 10% in a spike means the server choked)

API health score

Good95% or more
Watch80% – 94%
BadUnder 80%

Glossary

TermPlain meaning
RPS (requests/sec)How many requests the server finished per second. Throughput.
LatencyTime from sending a request to receiving the response.
AverageMean latency. Hides slow outliers, so also look at p95 / p99.
p50 / p90 / p95 / p99Percentiles. p95 = 300 ms means 95 of 100 requests were faster than 300 ms. p99 shows the slowest 1%.
Concurrent users / VUsHow many simulated users send requests at the same time. Each waits for its response before sending the next.
Error / drop rateShare of requests that failed (5xx or timeout).
2xx / 3xx / 4xx / 5xxSuccess / redirect / client error (bad request, 401 unauthorised, 404 not found) / server error.
429 Too Many RequestsThe rate limiter blocked the request.
TimeoutNo response within the time limit.
k6 checkA pass/fail test inside a k6 script, e.g. "status is 200".
k6 thresholdA rule for the whole run, e.g. p95 < 500 ms. k6 marks the run failed if it is broken.
Spike / stress / soakSudden burst / step-by-step increase to the limit / steady load for a long time.
SLAService level agreement: the promised performance, e.g. "under 1% errors".
IndexA sorted lookup structure that lets MongoDB find documents without reading all of them.
IXSCAN / COLLSCANQuery used an index / query read the whole collection.
Broken referenceA document stores the id of a record that no longer exists.

Dummy Data & Purge #

How test documents are recognised, counted and removed.

What counts as test data

A document counts as test data (and will be purged) if any of these is true. The first rule covers everything the Collections Seeder creates; the others match the ids and codes written by the built-in sample seeders.

FieldRule
isPerformanceTestDatais true (set on everything the studio seeds)
studentId / customStudentIdstarts with PERF_STU_
teacherIdstarts with PERF_TEA_
staffIdstarts with PERF_STAFF_
emailends with @bongo-test.local
classCodestarts with CLS_
subjectCodestarts with SUB_
schoolCodestarts with SCH_PERF_

The CLS_ and SUB_ rules match by prefix only. If your real data uses class codes starting with CLS_ or subject codes starting with SUB_, Purge will delete them too. Check Inventory's "Dummy Test" column before purging.

Purging

  1. Open the purge dialog

    Home → Test Purge card → Purge All.

  2. Confirm

    Yes, Purge All Test Data runs deleteMany with the rules above on every collection.

  3. Verify

    The Test Data card should show 0. Inventory's "Dummy Test" column should be empty.

From the terminal: npm run clean does the same.

Technical Reference

Architecture #

How the pieces fit together.

Browser
The studio UI (static files)
  • index.html · app.js
  • Chart.js · Cytoscape
  • EventSource for live logs
REST + SSE
Studio server :3333
Node.js · Express 5 (src/server.js)
  • autocannon: load, spike, stress, benchmark
  • axios: scanner, rate limiter, login
  • k6 CLI: Cloud Testing
  • Mongoose: stats, seeding, audits
  • Event bus → live stream
HTTP · MongoDB driver
Target backend
Base URL of the active environment
MongoDB
DB link of the active environment

What happens when you click a button

  1. The browser calls the studio server

    For example POST /api/test/run with the route, users and duration.

  2. The server runs the engine

    autocannon, axios, k6 or Mongoose does the real work against the target backend or MongoDB. The browser never talks to the target directly, so there are no CORS problems.

  3. Progress streams back live

    The engine writes to an internal event bus; GET /api/events streams it to the Live Operation Stream with Server-Sent Events.

  4. The result is returned and saved

    The response carries the result for the screen; most test kinds are also written to reports/ for Test History.

Frameworks & Libraries #

Everything the studio is built with, and what each part does here.

Server (Node.js, from package.json)

LibraryVersionRole in the studio
Node.js (ES modules)18+Runtime for the server and the CLI.
Express5.xWeb server: serves the UI, the REST API and the live event stream.
Mongoose8.xMongoDB connection: stats, seeding, purge, index audit, relationship map.
autocannon7.xFast HTTP load generator for load, spike, stress, smoke and the endpoint benchmark.
k6 (external CLI)installed separatelyGrafana's scriptable load-testing tool, used by Cloud Testing.
axios1.xHTTP client for the API scanner, rate-limiter audit, online checks and login.
@faker-js/faker9.xGenerates realistic names, numbers, dates and text for dummy data.
xlsx (SheetJS)0.18.xReads and writes Excel/CSV files for the API route directory.
bcryptjs3.xHashes the default password of users created by the multi-tenant sample seeder.
cors2.xAllows cross-origin calls to the studio API.
dotenv16.xOnly for the one-time import of an old .env file.
chalk · ora · cli-table35 · 8 · 0.6Colours, spinners and tables for the terminal menu (CLI).

Web UI (loaded from CDNs, no build step)

LibraryRole
Vanilla JavaScriptAll screen logic in app.js; no framework, nothing to compile. Edit and reload.
Tailwind CSS (Play CDN)Utility classes for layout and spacing in the markup.
style.cssThe studio's design system: cards, KPIs, buttons, chips, tables, gauges (plain CSS).
LucideThe line icons.
Chart.jsHome "Largest Collections" chart and the k6 dashboard charts.
Cytoscape.js + dagreDraws and lays out the Connected Collections map.
SheetJS (browser)Reads uploaded Excel/CSV files and builds the downloadable templates.
Roboto · Roboto MonoFonts (Google Fonts).
Server-Sent EventsBrowser-native live stream for logs and progress.

Because the UI libraries come from CDNs, the studio needs internet access in the browser. Charts and the relationship map can take a second or two to appear on a slow connection.

Project Structure #

Where to find things in bongo_performance_suite/.

bongo_performance_suite/ ├── package.json npm scripts and dependencies ├── README.md short guide (Bengali) ├── k6/spike_test.js standalone k6 spike script example ├── deploy_templates/ nginx, PM2 and Docker examples for the backend ├── reports/ saved test results (*.json) → Test History └── src/ ├── server.js Express server: UI, REST API, live event stream ├── cli.js interactive terminal menu (npm run menu) ├── config/ │ ├── environments.json all settings: environments, routes, auth │ ├── environmentManager.js reads/writes settings, API directory │ └── index.js live getters over the settings file ├── seeder/ built-in sample seeders; cleaner.js = purge ├── load_tests/ smoke, load, spike, stress, rateLimit, endpointBenchmark, │ apiScanner, k6Runner, fullBenchmark ├── auditor/ dbAuditor, relationMapper, reportGenerator ├── utils/ db, eventBus, reporter, reportHistory, authTokenManager └── public/ the web UI ├── index.html · app.js · style.css the studio └── docs.html · docs.css · docs.js this documentation

Where Data Is Stored #

What survives a restart and what does not.

LocationContentsLifetime
src/config/environments.jsonEnvironments, DB links, default tokens, test login, seeder defaults, API directory, login settingsPermanent (plain text, contains secrets)
Browser localStorage bongoStudio.settingsCopy of the settingsPer browser, until site data is cleared
reports/*.jsonSaved load, spike, benchmark, k6 and scan runsUntil deleted in Test History
Server memoryAuth tokens, latest k6 run (and /metrics values), latest API scan, relationship cache (5 min), stats cache (10 s)Lost when the studio server restarts
System temp folderThe k6 script and summary during a runDeleted when the run ends

Not stored anywhere: Load & Spike stress/rate-limiter results, Index Auditor results and the Executive Report itself (generate it again any time).

Server API Reference #

The studio's own REST API (on port 3333). The UI uses these; you can call them from scripts too.

Live stream, environments and stats

MethodPathPurpose
GET/api/eventsServer-Sent Events: log, progress, metrics
GET/api/environmentsAll environments and the API directory
POST/api/environments/activeSwitch the active environment
POST/api/environments/updateUpdate fields of one environment
POST/api/settings/globalSeeder defaults
POST/api/environments/test-connectionPing a Base URL and test a DB link
POST/api/environments/apis/import · /delete · /clearManage the API directory
GET/api/statsBackend online check + database and dummy-data stats

Database

MethodPathPurpose
GET/api/collections/dynamicCollections in the active database
GET/api/collections/relationsRelationship map (?force=true skips the cache)
GET/api/collections/relations/summaryCached summary for Home
GET/api/collections/relations/orphansBroken-reference counts
POST/api/seed/masterSeed all collections (volume)
POST/api/seed/generic/:collectionSeed one collection (count)
POST/api/seed/:entityBuilt-in sample seeders for a preset schema (students, attendance, teachers, …)
POST/api/cleanPurge all test data
GET/api/auditRun the index audit

Testing and reports

MethodPathPurpose
POST/api/test/runLoad / spike / stress / rate-limit / smoke test
POST/api/benchmark/run · /abortEndpoint Benchmark
GET/api/benchmark/statusIs a benchmark running?
POST/api/scanner/run · /abortAPI Health Scanner
GET/api/scanner/latestLatest scan summary
GET/api/k6/templates · /api/k6/statusk6 presets and state
POST/api/k6/run · /api/k6/abortRun or stop a k6 test
GET/metricsPrometheus text format
POST/api/promql/querySimplified PromQL lookup
GET/api/history · /api/history/:fileSaved runs list / one run
GET/api/history/:file/downloadDownload a saved run
DELETE/api/history/:fileDelete a saved run
GET/api/reports/recentRecent runs for Home
POST/api/report/generateBuild the Executive Report
GET/api/auth-tokenToken state and login settings
POST/api/auth-token/config · /login · /manual · /clearManage the token
Example: run a 20-second load test from the terminal
curl -X POST http://localhost:3333/api/test/run \
  -H "Content-Type: application/json" \
  -d '{"type":"load","targetUrl":"http://localhost:5000/api/v1/users","connections":50,"duration":20}'

Command Line (CLI) #

Every core action is also available from the terminal, using the active environment's settings.

CommandWhat it does
npm startStarts the web studio on port 3333 (same as npm run ui / npm run dev).
npm run menuInteractive terminal menu with 12 numbered actions (same as npm run cli).
npm run seedBuilt-in sample seeders: students + attendance (defaults from Settings).
npm run seed:studentsSample students only. Custom count: node src/seeder/studentSeeder.js 5000.
npm run seed:attendanceSample attendance logs only.
npm run cleanPurge all test data (same rules as Purge All).
npm run test:smoke10 users for 10 s against the Base URL.
npm run test:load50 users for 20 s.
npm run test:spike300 users for 15 s.
npm run test:stressFour stages up to 500 users.
npm run test:ratelimit550 requests, counts 429 responses.
npm run audit:dbIndex audit in the terminal.
npm run test:fullSmoke, load, spike and rate-limiter tests one after another (stops if the smoke test fails).

Deployment Templates #

Ready examples for scaling the backend after testing shows its limits.

Nginx

deploy_templates/nginx/nginx.conf: load balancer with least_conn over backend instances on ports 5001–5003, plus request rate limiting (50 req/s per IP, burst 30).

PM2

deploy_templates/pm2/ecosystem.config.cjs: cluster mode, one instance per CPU core, restart when memory passes 1 GB.

Docker Compose

deploy_templates/docker/docker-compose.yml: Nginx load balancer, two backend containers and Redis.

The templates are written for a Node.js backend. Before using them, change the build folder, start script and ports to your own project. For backends in other languages, the Nginx file still applies; PM2 and the Compose file need your own start command or image.

Typical loop: stress-test one instance → note the breaking point → run more instances behind Nginx or PM2 → stress-test again and compare in Test History.

Help

Troubleshooting #

Common problems and how to fix them.

ProblemLikely causeFix
Status pill shows OfflineThe backend is not running, or the Target URL is wrong.Start the backend; check the Target field and Settings → Test Connection.
Home cards stay at 0No or wrong DB link, or the database is empty.Settings → MongoDB Connection String → Test Connection → Save → Set as Active.
Every request returns 401 / 403No token, or it expired.Auth & Tokens → Log In Now, then run the test again.
Login fails with 429The backend's login rate limit was hit.Wait until the limit resets; avoid repeated logins.
Many 429s in a load testThe global rate limiter is blocking your IP.Wait for the window to reset, or test against a local backend.
Load test shows 0 requestsNothing answered at the route URL.Check the backend is up and the path is correct.
Cloud Testing error "spawn k6 ENOENT"k6 is not installed or not on the PATH.brew install k6, then restart the studio server.
"Another k6 test is already running"A previous run is still active.Click Abort Test and try again.
Executive Report shows no load dataNo k6 run since the server started.Run a Cloud Testing preset and an API scan, then regenerate.
Hand edits to environments.json disappearThe browser's saved copy is re-applied on load.Edit through the Settings screen, or clear this site's data.
A screen says "Restart the studio server"The server is running older code than the UI.Stop it (Ctrl + C) and run npm start again.
Charts or the map do not appearCDN scripts load slowly or are blocked.Wait a moment; check internet access and ad-blockers.
Port 3333 already in useAnother studio instance is running.Close it, or start with UI_PORT=4000 npm start.

When in doubt, look at the Live Operation Stream at the bottom of the studio and the terminal where npm start runs. Errors are logged in both.

FAQ #

Short answers to common questions.

Which backends can I test?

Any backend that serves an HTTP API, in any language or framework: Node.js, Python, PHP, Java, Go, .NET, Ruby and more. The database screens need MongoDB. See Supported Backends for the full list and the limits.

Is it safe to run against production?

Read-only screens (Home, Inventory, Index Auditor, Connected Collections, a GET-only scan) are safe. Load tests affect real users, and seeding/purge change real data. Only do those on production with a plan and approval.

Will Purge delete my real data?

Only documents matching the test-data rules are deleted. Real records are safe unless they happen to match a rule, such as a class code starting with CLS_. See Dummy Data & Purge.

What is the difference between Load & Spike Testing and Cloud Testing (k6)?

Load & Spike uses autocannon: quick, no installation, GET only, simple scenarios. Cloud Testing uses k6: scriptable in JavaScript, checks and thresholds, exportable for CI, and it feeds the Executive Report. k6 must be installed.

How many users should I test with?

Start with your real peak (for example the number of people active at the same time during your busiest hour), then try 3–5× for a spike. "Concurrent users" here send requests without pause, so 50 test users are much heavier than 50 real people.

Why are my results different every time?

Network, caches, other traffic and your own computer all add noise. Run each test two or three times with the same settings and compare averages. Test from a machine that is not busy with other work.

Can I run the k6 script without the studio?

Yes. Click Export .js in Cloud Testing and run k6 run file.js in a terminal or a CI pipeline (GitHub Actions, GitLab CI).

How do I add or update this documentation?

Edit src/public/docs.html. Each <section class="doc-section"> becomes a sidebar entry target, and its <h3> headings become the "On this page" list and search results automatically. Reload the page to see changes; no restart is needed.

Bongo Performance Studio documentation · Updated November 2026 Back to Studio