Skip to content

API Performance

Test: 1 July 2026 · one user · six months of data (200 factories, 4,000 machines, 5,000 tasks)

Results

# Screen Before After Status
1 Task list 437 ms 23 ms Fixed
2 User signup (50 people at once) 67 s 1.25 s Fixed
3 Factory list 345 ms 24 ms Fixed (target 30 ms)
4 Machine list 351 ms 320 ms Fixed
5 Notifications (heavy use) 10 ms 4 ms Fixed
6 Factory mind map blocks event loop 0.79 s max under 6 concurrent renders Fixed

Task list under load (1 user, 1 minute test): 417 ms → 60 ms.

What was wrong

Screen Problem
Task list Server queried the database separately for every row (notes, factory, assignees).
User signup Password + QR generation froze the app for everyone else.
Factory list Sends modules, areas, categories the list screen never shows.
Machine list Counts every machine on every page open.
Notifications Loads all history, no date limit.
Mind map The async endpoint called synchronous Graphviz rendering directly on the event loop. Fixed 2026-07-01: a bounded async semaphore (MINDMAP_RENDER_CONCURRENCY, default 1) gates render slots; token validation, DB reads, and Graphviz PDF work run in Starlette's threadpool only after a slot is acquired, so queued requests no longer hold database sessions. Output uses per-request temporary directories.

What to do next

Screen Fix
User signup Fixed — async QR worker; benchmark: scripts/performance/run_signup_benchmark.py
Factory list Fixed — lightweight FactoryListItem schema + selectinload detail query.
Machine list Fixed — cursor pagination without default COUNT(*); exact totals opt-in via include_totals=true.
Notifications Fixed
Mind map Fixed - bounded threadpool render + isolated temporary render directory

Factory list follow-ups

The list latency fix shipped on 30 June 2026. Before closing this item, complete these checkups:

# Checkup Owner Status
1 Confirm with the mobile client that GET /api/factories no longer needs nested relation data (sectors, production_categories, production_areas, modules, sub_modules) in the list payload. Detail remains on GET /api/factories/{id}. Mobile + backend Open
2 Split get_factory() into a lean lookup (existence / ID checks on write paths) and a detail loader with selectinload for all five M2M relations. Avoid loading relations on quote, task, and calendar validation calls. Backend Open
3 Add contract tests: list response shape (FactoryListItem scalars only, no relation keys) and pagination headers (X-Total-Count, X-Total-Pages, X-Current-Page). Backend Open
4 Extend the detail query-efficiency test to seed all five M2M relations, not only sectors, so selectinload regressions on any collection are caught. Backend Open
5 Decide whether consultants must be restricted on GET /api/factories/{id} to match list behavior (created_by == current_user). Today list filters consultants; detail does not. Product + backend Open

Run tests: volume-testing.md

Machine list pagination contract (2026-07-01)

Default GET /api/machines no longer runs COUNT(*) or returns X-Total-Count / X-Total-Pages.

Mode Query param Response headers
Default none X-Current-Page, X-Has-Next-Page
Exact totals include_totals=true above plus X-Total-Count, X-Total-Pages

T1 benchmark rerun: docs/volume-results/run-20260701-121011/ — machine list p95 351 ms → 320 ms (15 samples, 1 client).

Factory mind map render safety (2026-07-01)

Local verification with Graphviz installed (dot 15.0.0, Python graphviz==0.20.3) against uvicorn on port 8002:

Probe Result
Single real mindmap request HTTP 200, 165 ms, 146 KiB PDF
Six concurrent real mindmap requests all HTTP 200, max 790 ms
/api/openapi.json during six mindmap requests HTTP 200, 4 ms
/api/factories?limit=1 during six mindmap requests HTTP 200, 17 ms

The endpoint no longer blocks the event loop or holds database sessions while queued. It still performs CPU and process work, so high-volume PDF generation should remain bounded or move to a job queue if usage grows.

Deployment dependencies

Requirement Source Notes
Python graphviz==0.20.3 requirements/runtime.txt Wrapper only; installed with pip install -r requirements/runtime.txt
Graphviz dot binary OS package Required at runtime; e.g. apt install graphviz or brew install graphviz
MINDMAP_RENDER_CONCURRENCY Environment Optional; default 1; caps concurrent mindmap renders per worker process