Skip to content

perf: cut extra requests, large list rendering and CI checkout time - #323

Merged
MrYuion merged 5 commits into
developfrom
fix/performance-followup
Oct 21, 2026
Merged

MrYuion merged 5 commits into
developfrom
fix/performance-followup

Conversation

@MrYuion

@MrYuion MrYuion commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator

Problem

A follow-up audit after #322 found these performance problems:

  • Each upload read the whole file into memory and copied it to an unused blob before the upload started. A 500 MB file held about 1 GB.
  • Opening a system sent 7 requests, including the full module list. Any action, such as turning on one module, reloaded all 5 lists.
  • Driver, module and user pages sent count queries for lists that were already loaded or not needed yet. User lookups in metadata and settings were not shared while in flight. The default locale downloaded twice.
  • Support zone searches loaded every page at the default size, one after another, for each group. The resource import check sent up to 1000 emails in one URL (about 30 KB) and read only one page.
  • Group membership tables rendered up to 1000 rows and checked them on every tick. The metadata history modal built 2 options per version (up to 5000 versions). The bulk add checks ran on every tick, and its status list copied every status on each update.
  • About pages imported marked and Shiki (67 KB gzip) even without a description.
  • The BUILD checkout fetched 562 MB, mostly deploy branches. git-cliff took 17 s before the build. Monaco copied 14 MB, mostly files the app never loads.

Solution

One commit per area:

  • perf: drop redundant requests and upload buffering: pass the File to the upload library at once. Remove blob-util. Share user lookups. Use the loaded totals for the driver and module tab counts. Load the user group list when its tab opens. Reuse the bundled default locale. Remove the unused API key users query.
  • perf(systems): …: load the module, zone and trigger lists when their tab opens. Settings, modules and triggers each reload only after an action that changes them.
  • perf: page support zone searches …: ask for zone pages of 1000. Check resource emails 100 at a time, read every page and match through a map.
  • perf(ui): …: 72 px virtual rows on the four group membership tables. The history selects render 20 options and the selected one while closed (mat-select does not open without options). The bulk add checks become computed, and the status list uses virtual rows with one signal per row. The markdown pipe imports its renderer on first use.
  • perf(build): …: shallow checkout plus git fetch --unshallow --tags for the branch. git-cliff runs alongside the build. Skip the Monaco ts/css/html workers and nls files. Remove the Playwright browser cache and the fixed 500 ms e2e wait.

Notes for review

  • Repository drivers list: still loads on open. Its tab count needs the full list, and there is no count endpoint.
  • Metadata tab: each item page still downloads the full metadata to count it. A fix needs a count option in the API.
  • Not changed: caching applications per domain and skipping the reconnect access reload. The gain is small against the extra cache rules.
  • Out of scope: e2e sharding, the other ~130 waitForTimeout calls, the CodeQL v3 upgrade, and running TEST on develop pushes.

Checks

  • Type check, lint and Vitest: tsc, the ngc template check and lint pass. Vitest passes, 1038/1038, including new specs for the system tab loading and for shared user lookups. Both fail without the fix.
  • e2e: Chromium and mobile Chrome pass twice locally without the 500 ms wait: 111 passed, 1 skipped, about 55 s.
  • Changelog: the output from the shallow checkout is byte-identical to the one from a full clone.
  • Production build: passes. The Monaco copy is 5.7 MB (100 files, was 14 MB and 112 files). The markdown renderer chunk is reached only through import().
  • Visual check, mock mode:
    • User groups: 300 groups render as 16 DOM rows. A row with all 8 permissions fits.
    • Metadata history: with 3000 versions, the long task on open goes from 125 ms to none over 50 ms. Selections past the first 20 options still show, and the diff renders.
    • Bulk add: with 300 rows, the review checks update on edit and all 300 rows were created with 12 rows in the DOM.

Reviewed with sol-loop: 1 round per block (5 blocks) with gpt-6.1-sol.

Changes made by Claude Opus 5.5 (claude-opus-5-5) in Claude Code, running in T3 Code.

🤖 Generated with Claude Code

MrYuion and others added 5 commits October 21, 2026 15:30
- Uploads pass the File to the chunked upload library at once. They no
  longer read the whole file into memory and copy it to an unused blob.
  Remove the blob-util dependency.
- User lookups share requests that are in flight.
- Driver and module tab counts use the totals the state services already
  load, not a second count query.
- The user group list loads when its tab opens. Until then a single row
  query gives the count.
- The default locale reuses its bundled mappings instead of fetching the
  same file again.
- Remove the unused API key users query.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening a system sent 7 requests, including the full module list, and
any action reloaded all 5 lists.

- Load the module, zone and trigger lists when their tab opens. The item
  gives the module and zone counts, and a single row query gives the
  trigger count.
- Settings, modules and triggers each have their own change signal.
  Module actions reload modules, editing a module also reloads the
  associated settings, and trigger actions reload triggers. Zones and the
  metadata count reload when the item changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Support zone searches ask for pages of 1000. Each group loaded every
  page one after another at the default size, so a 2000 zone group took
  about 20 requests per search.
- The resource import check sent up to 1000 emails in one URL (about
  30 KB) and read one page. Send 100 emails per request, read every page
  and match through a map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- BUILD fetches only the branch history and tags (about 30 MB, not
  560 MB with the build/* deploy branches). The changelog is identical.
- git-cliff runs alongside the build. A failure still fails the step.
- Do not copy the Monaco ts, css and html workers or the translated nls
  files. The app uses JSON and YAML only. 14 MB to 5.7 MB.
- Remove the dead src/environments/dev asset entry.
- Remove the Playwright browser cache. A hit saved about 2 s.
- e2e: drop the fixed 500 ms wait after each page load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Group membership tables (group users and zones, user groups, zone
  groups) use 72 px virtual rows. Each row computes its permission
  labels once.
- The metadata history selects render 20 options and the selected one
  while closed. With 3000 versions, opening the modal no longer blocks
  for 125 ms.
- Bulk add: validation and duplicate checks are computed from the list
  signal instead of running on every tick. The status list uses virtual
  rows and one signal per row instead of copying all statuses per update.
- The markdown pipe loads marked and Shiki (67 KB gzip) on first use, so
  about pages without a description skip them.
- Domain applications: a click anywhere no longer writes the secret state
  once per row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
backoffice Ready Ready Preview Oct 21, 2026 4:39am UTC

@MrYuion
MrYuion merged commit 0e2f0ab into develop Oct 21, 2026
7 checks passed
@MrYuion
MrYuion deleted the fix/performance-followup branch October 21, 2026 04:58

This branch was successfully deployed

1 active deployment
Preview — bd719828 Deployed Oct 21, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant