Skip to content

perf: cut duplicate requests, render work and CI time - #322

Merged
MrYuion merged 3 commits into
developfrom
fix/performance-audit
Oct 16, 2026
Merged

MrYuion merged 3 commits into
developfrom
fix/performance-audit

Conversation

@MrYuion

@MrYuion MrYuion commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

Problem

An audit found these performance problems:

  • Each system, zone, module or driver page loaded its data twice. Each save reloaded it two or three times.
  • With a support group selected, each module search sent one request per system in the group.
  • Zone, group and user pages loaded full tab lists (up to 500–1000 rows) before the user opened the tab.
  • Tables, the settings form and lists did avoidable work on every change detection pass.
  • The app loaded a 1.09 MB icon font, Roboto from Google Fonts and a 149 KB Shiki wasm.
  • CI ran e2e on 1 worker (about 7 of 8.4 minutes). The Nx cache step saved nothing.

Solution

Data (perf:)

  • Load each item and its settings together, then set the item once. A save sets the item at once. A background refresh sets it again only if the settings changed.
  • Cache the support group's modules. Clear the cache on group or section change and after a module save.
  • Send count queries first, and load full tab lists only when the tab opens (the domain page already does this). Remove duplicate trigger and metadata calls.
  • Do not make sys admins wait for all groups at sign-in. Bound the sign-in retry loop.
  • Reload the group sidebar only after items change.
  • Export the zone tree one level at a time. Import each level 4 zones at a time. Remove cascade systems 4 at a time.
  • Skip polls when the browser tab is hidden or a request is in flight.
  • Fix: cluster_nodes got the same mutated object, so its views did not update.

UI (perf(ui):)

  • Memoise the settings YAML validation.
  • Use one hover listener per table instead of one per cell. Sort with precomputed keys and a shared Intl.Collator. Keep the selection when polled data refreshes.
  • Add OnPush to simple-table, virtual-scroll, icon and the line graph.
  • Use virtual rows for the zone systems, zone children and bulk import tables.
  • Show at most 50 timezone options. Draw the line graph only when its data changes.

Build and CI (perf(build):)

  • Icon font: pin the opsz axis to 24 (1.09 MB → 422 KB).
  • Fonts: serve Roboto with @fontsource-variable/roboto and bundle the icon and Fira Code CSS. This removes the render-blocking stylesheets.
  • Shiki: use the JavaScript regex engine instead of the wasm. All 56 languages compile.
  • e2e: run on 3 workers.
  • Nx cache: fix the cache path in test.yml.
  • Playwright: install and cache only the browsers in use.
  • PR runs: cancel superseded runs.
  • CodeQL: run once per push, with no install step and a 10-minute timeout.
  • Bun cache: remove it. Restore and save took 20–30 s against a 3 s install.

Notes for review

  • build.yml Nx cache: I removed the step instead of fixing it. Nx does not hash the gitignored src/env/version.ts, so a restored build could deploy an earlier commit's version info.
  • Icon font preload: removed, because the font now has a hashed URL.
  • Bun install time: a cold bun install on CI is estimated at 10–15 s, not measured. Check the first run.
  • paths-ignore for docs/** and *.md: develop has no required status checks, so these runs are safe to skip.
  • Out of scope: develop deploying the development build, trimming the Monaco assets, and the bulk modal validation getters.

Checks

  • tsc, template check, lint and production build: pass.
  • Vitest: 1023/1035 pass. The 12 failures are in cascade-locale.spec.ts and also fail on develop.
  • e2e: passes on 3 workers locally in 2.1 min (CI took 7 min on 1 worker). One test failed once and passed on retry.
  • Visual check: mock mode (?mock=true). The zone tables with virtual rows, the lazy tab counts, the self-hosted Roboto and the new icon font look correct. Not checked by eye: the bulk import list and the line graph.

Reviewed with sol-loop: 4 rounds with gpt-6.1-sol on high.

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 3 commits October 16, 2026 20:25
- Load an item and its settings together and set it once, so state
  services reload once per open and per save instead of two or three
  times. A background refresh shows settings that changed since load.
- Cache the support group's modules instead of walking every system on
  each search.
- Count first and load full zone, group and user tab lists only when the
  tab opens; drop duplicate trigger and metadata calls.
- Publish sys admins before their groups load; bound the retry loop.
- Reload the group sidebar only after items change.
- Walk zone export one level at a time, import each level 4 at a time,
  and remove cascade systems 4 at a time.
- Skip polls while the tab is hidden or a request is in flight.
- Set cluster_nodes to a new object so its views update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Memoise settings YAML validation instead of parsing on every tick.
- Use one hover listener per table instead of one per cell; sort with
  precomputed keys and a shared collator; keep the selection when
  polled data refreshes.
- Use a passive scroll listener in virtual-scroll and automaticLayout in
  the diff viewer.
- Add OnPush to simple-table, virtual-scroll, icon and the line graph.
- Use virtual rows for zone systems, zone children and the bulk list.
- Show at most 50 timezone options.
- Draw the line graph when its data changes, not every 300 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Pin the icon font opsz axis to 24 (1.09 MB to 422 KB) and bundle the
  icon and Fira Code stylesheets.
- Replace Google Fonts Roboto with @fontsource-variable/roboto.
- Use the Shiki JavaScript regex engine instead of the Oniguruma wasm.
- Lower the initial budget warning to 750 kB.
- CI: run e2e on 3 workers, fix the Nx cache path, install and cache
  only the Playwright browsers in use, cancel superseded PR runs, run
  CodeQL once per push without installs, and drop the bun cache.

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

vercel Bot commented Oct 16, 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 16, 2026 9:26am UTC

@MrYuion
MrYuion merged commit f26bc80 into develop Oct 16, 2026
7 checks passed
@MrYuion
MrYuion deleted the fix/performance-audit branch October 16, 2026 09:59

This branch was successfully deployed

1 active deployment
Preview — ac10ff11 Deployed Oct 16, 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