Full repository performance and resource-cost audit
For the-platform project: a microservices CRM platform — FastAPI + asyncpg +
PostgreSQL + Redis + RabbitMQ backend services, a React/Vite/TS frontend
(the-frontend), Docker/Kubernetes/Helm infrastructure, load testing with k6
in load-testing/.
ROLE
The company the product is built for is extremely sensitive to the
consumption of compute resources (CPU, RAM, network traffic, infrastructure
cost) — performance and economy are treated as a first-class priority, not as
tech debt to handle "someday later". The audit must find real, measurable
problems tied to file:line and with a quantitative impact estimate (latency,
CPU, RAM, number of DB queries, traffic size), not produce a generic "best
practices" checklist without verification against the concrete codebase.
INPUT
$ARGUMENTS — optionally a path to the previous audit report or to
load-testing/reports for a "before → after" comparison. If not passed, look
for it yourself: load-testing/ANALYSIS_GUIDE.md, load-testing/reports, and
any previous performance-audit reports mentioned in the dialogue or the
repository.
This is an audit of the WHOLE repository. If the task actually concerns only
one feature/branch/PR — this is not the right skill; use
performance-audit-feature instead of a full review of the entire codebase
(otherwise the scope will be excessive and the findings will not be tied to
what really matters to check).
KEY PRINCIPLE: MEASURE, DON'T GUESS
The main reason performance audits fail or, conversely, do harm is two
symmetric failures: (a) findings without proof of real impact ("this may be
slow") and (b) blindly piling on "optimizations" (caching, memoization,
denormalization) where there is no measured problem, which complicates the
code and creates a new class of bugs (stale cache, race condition) for a
nonexistent gain. Neither failure should occur:
- For each finding where technically possible, confirm the impact by
measurement: EXPLAIN ANALYZE for a SQL query, profiling (py-spy/cProfile)
for a CPU hotspot, the real bundle size for the frontend, the output of
existing k6 scenarios from
load-testing/ for the load characteristics of
the API. A finding without a number is a hypothesis, not a finding; flag it
explicitly as "not confirmed by measurement" and state what is needed to
confirm it.
- Do not propose optimization where there is no proven problem. If code is
"non-idiomatic" but is not on a hot path and does not consume noticeable
resources — record it as cosmetic/low, not as a performance finding. Three
identical lines are better than premature abstraction; the same principle
applies to caches and memoization.
- Distinguish "theoretically suboptimal" from "really expensive at the
current/expected data volume". An N+1 query on a table with 10 rows in the
dev environment is not the same as an N+1 on a contacts/deals table with
hundreds of thousands of rows in prod. Explicitly state at what data volume
the finding becomes critical.
- If an optimization was already made earlier (check git log/comments) —
check whether it later regressed (e.g. a cache was added but invalidation
was forgotten when a neighboring module was refactored).
- State the status explicitly: "confirmed by measurement" / "plausible but
not measured" / "not a problem at the current data volume" / "already
optimized correctly".
METHODOLOGY: THREE INDEPENDENT PASSES
Run the audit by three independent methods and do not let one pass substitute
for another — they have different blind spots.
PASS 1 — Instrumental analysis and profiling
- Backend (Python/FastAPI): enable SQL logging
(echo=True/aiosqlalchemy debug) on the key scenarios and find N+1 queries
and queries without LIMIT/pagination; where a DB connection is available —
run EXPLAIN ANALYZE on the most frequent/heavy queries and record missing
indexes (a seq scan where an index scan is expected); use py-spy/cProfile to
profile CPU on suspect hot paths (webhook handlers, sync jobs,
serialization of large responses).
- Database: pg_stat_statements (if enabled) for the top queries by total
time and by number of calls; a list of tables without indexes on the columns
used in WHERE/JOIN/ORDER BY (cross-check with each service's migration
schema); table size and growth over time, if metrics are accessible.
- Redis: patterns of keys without TTL (risk of unbounded memory growth),
KEYS/SCAN commands over the whole key space in the hot path, value size
(serializing whole objects instead of the needed fields).
- RabbitMQ: prefetch/QoS configuration, queue depth, retry policies
without backoff/DLQ.
- Docker images: dive or
docker history on each built image — layer
sizes, unused build tools and dev dependencies that ended up in the final
image; compare against multi-stage build where it exists/is absent.
- Frontend (the-frontend): build the production bundle and analyze it
(
vite build --mode production + rollup-plugin-visualizer/
source-map-explorer, if wired in, or manual analysis of dist/ by chunk
size); Lighthouse (or an analogue) on the key pages for LCP/TBT/bundle size
metrics, if it is possible to bring up the frontend locally.
- Load testing: the repository already has k6 scenarios and reports in
load-testing/ (see load-testing/ANALYSIS_GUIDE.md, load-testing/k6,
load-testing/reports). Read the existing reports — which bottlenecks were
found earlier and not resolved; if the environment can be brought up — re-run
the current scenarios and compare against the saved baseline reports.
- Kubernetes/Helm: checkov/kube-linter or a manual review of the charts
for resources requests/limits (empty/missing — a risk of noisy neighbor and
throttling; oversized — direct overspend of the infrastructure budget),
liveness/readiness probe intervals (too-frequent probes = constant
background load on N replicas), HPA configuration and its thresholds.
PASS 2 — Manual line-by-line code review
Split the codebase into independent zones and review EACH (not diagonally,
not relying only on grep patterns):
- Each backend service separately (gateway, all
*-service directories in
services/).
- Frontend / SPA (
the-frontend).
- Background handlers, bots, and external-API integrations
(telegram-bot-service, telegram-connector-service,
whatsapp-personal-service, kommo-integration-service,
verification-bot-service, ai-bot-service) — this is the code with the
highest risk of constant background load (polling, syncs, long-polling), not
just request-response on demand.
- Shared libraries (
libs/shared_auth, libs/shared_metrics) — code that
runs on EVERY request of EVERY service; even a small inefficiency here is
multiplied by the number of services and replicas.
- Infrastructure configs (
helm/, docker-compose*.yml, deploy/,
infrastructure/).
For each zone, look for (detailed checklist below) and for each finding
record: file:line, problem type, a quantitative impact estimate (or a "not
measured" mark), severity, status (see above).
PASS 3 — Architectural review
Independently of the line-by-line review, assess whether the current
architecture can HOLD economy as load grows, not just be free of obvious
problems today:
- A "chatty" inter-service architecture: how many sequential synchronous HTTP
calls one user request makes through gateway → services → services (build
the chain for the 2-3 most frequent scenarios: login, deals/leads list,
sending a chat message). Every extra hop is latency and CPU/network,
multiplied by traffic.
- Whether a fixed replica count is justified (in
docker-compose.microservices.yml the gateway is brought up in 3 instances,
etc.) — is there real load data justifying this number, or is it "just in
case"? The same for analogous decisions in helm-values (replicaCount).
- Duplication of shared libraries (shared_auth, shared_metrics) across
services instead of a single package — if a performance fix/optimization is
made in one copy, does it propagate automatically to the rest, or does the
patch have to be rolled out N times (the same risk as for security patches)?
- A general caching strategy: does one even exist as a deliberate decision
(what is cached, at what level, with what invalidation), or is a cache added
pinpoint and unsystematically wherever someone once noticed a slowdown?
- Combining OLTP load (transactional services) and heavy analytics (Superset,
analytics-service) on the same DB/instance — contention for resources.
- Presence of a process: is load testing (k6 in
load-testing/) run regularly
or one-off; is there a performance budget for the frontend bundle and API
latency, enforced in CI rather than only "by feel"?
DETAILED CATEGORY CHECKLIST
- Async backend: blocking calls in the event loop — synchronous HTTP
clients (requests, etc.) instead of httpx.AsyncClient/aiohttp inside async
handlers; synchronous I/O (opening files, time.sleep, synchronous DB
drivers) inside
async def; CPU-heavy operations (parsing large JSON/XML,
encryption, image processing) on the event loop without
ThreadPoolExecutor/ProcessPoolExecutor; sequential await where the calls
are independent and could go in parallel via asyncio.gather (a typical
pattern in the gateway when calling several services to assemble one
response).
- Database (PostgreSQL) — N+1 queries (a loop with a DB query inside where
one JOIN/
selectinload/joinedload would do); missing indexes on columns
in WHERE/ORDER BY/JOIN, especially on foreign keys (user_id, tenant_id,
integration_id) and multi-tenant filtering; SELECT */full serialization
where 2-3 fields are needed; list endpoints without pagination/LIMIT;
connection pool size relative to the number of replicas and the PostgreSQL
limit; long transactions with external HTTP calls inside (a categorically
unacceptable pattern); repeated identical queries within one request-response
cycle.
- Caching (Redis) — keys without TTL; absence of a cache for expensive,
frequently repeated, and rarely changing computations (dashboard aggregates,
reference data, roles); cache stampede (no lock/single-flight on
expiration); a cache without invalidation when the source data changes
(record separately as a correctness problem, not only a perf one); KEYS/SCAN
over the whole database in the hot path; storing large blobs instead of
specialized storage.
- Inter-service communication (HTTP) — absence of timeouts on outbound
requests; absence of retry with exponential backoff (or retry without
backoff — a thundering herd during a partial incident); duplicate calls to
one service instead of a batched call; full forwarding of heavy payloads
where only part of the data is needed.
- Queues (RabbitMQ) and background handlers — prefetch/QoS (too large
overloads the consumer, too small underuses parallelism); poison message
without DLQ; external-API polling frequency (kommo-integration-service,
telegram-connector-service, whatsapp-personal-service) relative to the real
need, batch size, rate-limit handling (429/retries).
- Serialization and payload size — Pydantic models returning
significantly more fields than are actually used; logging large
objects/payloads in full in the hot path; absence of compression
(gzip/brotli) on the gateway for large JSON responses.
- Frontend (React/Vite/TS) — production bundle size and absence of
code-splitting/lazy-loading for rarely used routes; unoptimized
images/static assets; excessive re-renders on large lists/tables
(leads/deals) — absence of virtualization, new objects/callbacks in render
without memo where the profiler clearly shows a hotspot (do not add
memo/useCallback everywhere "just in case" — that also costs resources
without a measured benefit); waterfall data loading instead of parallel;
too-frequent polling where WebSocket/SSE would be more appropriate, or a
WebSocket with excessive reconnect/heartbeat.
- Docker images — final image size per Dockerfile (services/*,
the-frontend); absence of multi-stage build where build dependencies end up
in the final layer; an oversized base image (full OS instead of
slim/alpine/distroless), if that does not create compatibility problems.
- Kubernetes/Helm — resources requests/limits: missing (noisy neighbor,
OOM-kill) and, at the same time, oversized "with a margin" without a basis
in real consumption; liveness/readiness/startup probe intervals/timeouts on
a large number of replicas; replicaCount and HPA thresholds — are they
justified by numbers; init containers and pod startup logic — do they block
readiness longer than necessary?
- Observability as a source of overhead — metric cardinality
(shared_metrics): high-cardinality labels (user_id, request_id as a label
instead of a value); trace sampling frequency/volume; logging volume and
level in prod (DEBUG logs "for convenience"); synchronous sending of
metrics/traces in the hot path instead of batching/async sending.
- Algorithmic efficiency and data structures — quadratic and
worse-complexity operations over collections that will become a bottleneck
at real data volumes (leads/contacts/chat-message lists grow over time);
repeated parsing/recomputation of the same data within one request;
unnecessary deep copying of large structures; absence of batching for bulk
operations (leads import, syncs with external CRMs) where the operation
volume is regularly large.
- Load testing and performance budgets — currency of the k6 scenarios
(load-testing/k6) relative to the current API contracts; discrepancy
between the bottlenecks documented in load-testing/reports and
load-testing/ANALYSIS_GUIDE.md and the current state of the code (are they
actually fixed, or did the report remain un-updated — "fixed on paper");
presence or absence of recorded performance budgets in CI (maximum bundle
size, maximum p95 latency) — without such a gate, performance regressions
slip into prod unnoticed.
EDGE CASES OFTEN MISSED
- "Runs fast on dev data" — the problem shows only at real customer data
volumes (thousands of leads, tens of thousands of chat messages); always
estimate the expected growth.
- Debug conveniences forgotten in prod: verbose logging, disabled response
compression, disabled cache "to make debugging easier" — and not turned back
on.
- Health/readiness probes that hit the DB or external services on every
N-second check, multiplied by the number of replicas — in total a noticeable
background load on the DB with no business value.
- Several independent services polling the same external API redundantly
instead of a shared cache/single synchronization point.
- Retry logic without backoff, amplifying load precisely at the moment of a
partial incident (when resources are already scarce).
- Heavy analytical queries (Superset/analytics-service) running on the same
DB/instance as the transactional load, during CRM peak load hours.
- "Optimization for optimization's sake": a cache/memoization/denormalization
added without a measured problem — increases the complexity and volume of
code that must be maintained and that itself consumes resources (cache
memory, synchronization), without a proven benefit. Record such findings
too — propose simplification.
- Configuration differences between environments (dev/staging/prod) in
docker-compose/helm-values — an optimization made for one environment may be
absent in another.
- Feature flags forgotten after experiments, doubling the work (writing to the
old and the new system at once "during the migration", which finished long
ago).
REPORT FORMAT
- Executive summary (for leadership, no technical jargon): what consumes
resources most noticeably, what can be optimized without risk to
functionality first, the approximate effect (in terms of
latency/load/infrastructure resources).
- KPI table: number of findings by severity (critical/high/medium/low),
number of findings confirmed by measurement vs "plausible but not
measured"; the approximate total resource savings from eliminating the
critical findings, if it can be estimated.
- If this is a re-audit — a comparison table "previous-report/load-testing
item → current state (file:line) → status (not fixed / on paper /
selectively / fixed)".
- A "fixed but not working" section separately (e.g. an index was added in the
migration, but the query still does a seq scan due to a type/function
mismatch in WHERE).
- Full list of findings tied to file:line, with a quantitative impact estimate
(or an explicit "not measured" mark and what is needed to measure it),
severity, and a concrete remediation recommendation (not "optimize the
query", but "add an index on (tenant_id, created_at)", "replace the N+1 with
selectinload", "move the external API call out of the transaction body").
- A "what was done well" section — efficient patterns in the codebase worth
replicating to other services rather than redoing.
- Action plan by timeframe: quick pinpoint fixes without regression risk
(indexes, timeouts, fixing N+1) — first; changes requiring testing under
load — second; architectural decisions (rethinking the caching strategy,
reducing the number of inter-service hops, a scaling plan) — as
leadership/team-lead-level decisions.
- A "methodology and coverage limitations" section — which tools and
measurements were used, which services/zones were NOT profiled or loaded and
why (no access to prod metrics, no ability to bring up the environment,
etc.), so the absence of findings in an uncovered zone does not read as
"everything there is optimal".
FINDING FORMATTING RULES
For each finding, the following are mandatory:
- The file path and line number (or range).
- The problem name and category (see the checklist above).
- A quantitative impact estimate: measured (number of DB queries, EXPLAIN
ANALYZE output, profiling time, bundle/image size in MB, p50/p95 latency) or
explicitly marked as an unmeasured estimate with justification for why it is
likely.
- The condition under which the problem becomes critical (data volume, number
of concurrent users, call frequency) — if it does not hold today but will
hold as things grow, state it explicitly; do not under- or over-state the
urgency.
- Severity with justification (what share of traffic/data is affected, which
resource is consumed: CPU, RAM, network traffic, number of DB connections,
infrastructure cost).
- Status relative to the previous audit/load-testing report, if applicable.
- A remediation recommendation — concrete and preserving the current
functionality (the audit should not propose changing the system's behavior,
only the efficiency of its implementation).
RUNNING THE AUDIT (practical instructions)
- Determine the scope: list all backend services (services/), the frontend
(the-frontend), shared libraries (libs/), background bots/connectors,
infrastructure configs (helm/, docker-compose*.yml, deploy/,
infrastructure/), existing load tests (load-testing/).
- Read the existing load-testing artifacts (load-testing/ANALYSIS_GUIDE.md,
load-testing/reports) BEFORE starting the manual review — it is a ready
source of already known bottlenecks; don't duplicate work, just check
whether they are resolved.
- Run the available tools of PASS 1 on each service/image/chart where possible
in the current environment; save the raw output for report appendices.
- Split the manual review of PASS 2 into independent chunks (by service/zone)
— if the Agent tool is available, launch several independent subagents on
different zones in parallel (in foreground, if the result is needed
immediately in this dialogue), so as not to miss volume and not to let one
agent "cut corners" across the whole codebase at once.
- Perform the architectural review of PASS 3 separately, independently of the
PASS 2 results.
- Consolidate all three passes into a single report per the format above,
remove duplicates, but do not merge findings of different natures (a tool
found a suspicious pattern ≠ manual review confirmed real impact — record
both facts if both exist, with the corresponding confirmation status).
- If this is a re-audit — be sure to re-verify EACH item of the previous
report and each finding from load-testing/reports against the current state
of the code, rather than relying on the status claimed by the team.
- Explicitly state which checks were NOT performed (no access to prod
metrics/pg_stat_statements, no ability to bring up the environment for
profiling or a k6 run, no data on real customer data volumes) — this is part
of an honest report, not its weakness.
- No recommendation should change the observable behavior/functionality of the
system — only the efficiency of the implementation. If an optimization
inevitably requires a behavior change (e.g. tightening default pagination) —
note this separately and explicitly.
This is an audit, not implementation: the developer makes the changes based on
the report, not you within this skill.
1---2name: performance-audit-full3description: Full performance and resource-cost audit of the entire the-platform repository (FastAPI/asyncpg/PostgreSQL/Redis/RabbitMQ backend services, the-frontend, shared libraries libs/*, Docker/Kubernetes/Helm infrastructure, k6 load testing in load-testing/) — three independent passes (instrumental profiling, line-by-line code review, architectural review), findings only with measurement (EXPLAIN ANALYZE, py-spy, bundle size, k6 runs), severity, file:line, and a final verdict. Use when asked to run a performance/resource-cost audit of the whole codebase or infrastructure, to check CPU/RAM/network-traffic/infrastructure-cost consumption, to find bottlenecks across the whole repository, to assess the economy of the architecture as load grows, or to re-verify the status of findings from a previous audit/load-testing reports — even if the user doesn't say the word "audit" literally, but says "why does the service eat so much CPU/memory", "let's look at the performance of the whole project", etc.4---56# Full repository performance and resource-cost audit78For the-platform project: a microservices CRM platform — FastAPI + asyncpg +9PostgreSQL + Redis + RabbitMQ backend services, a React/Vite/TS frontend10(the-frontend), Docker/Kubernetes/Helm infrastructure, load testing with k611in `load-testing/`.1213## ROLE1415The company the product is built for is extremely sensitive to the16consumption of compute resources (CPU, RAM, network traffic, infrastructure17cost) — performance and economy are treated as a first-class priority, not as18tech debt to handle "someday later". The audit must find real, measurable19problems tied to file:line and with a quantitative impact estimate (latency,20CPU, RAM, number of DB queries, traffic size), not produce a generic "best21practices" checklist without verification against the concrete codebase.2223## INPUT2425`$ARGUMENTS` — optionally a path to the previous audit report or to26load-testing/reports for a "before → after" comparison. If not passed, look27for it yourself: `load-testing/ANALYSIS_GUIDE.md`, `load-testing/reports`, and28any previous performance-audit reports mentioned in the dialogue or the29repository.3031This is an audit of the WHOLE repository. If the task actually concerns only32one feature/branch/PR — this is not the right skill; use33`performance-audit-feature` instead of a full review of the entire codebase34(otherwise the scope will be excessive and the findings will not be tied to35what really matters to check).3637## KEY PRINCIPLE: MEASURE, DON'T GUESS3839The main reason performance audits fail or, conversely, do harm is two40symmetric failures: (a) findings without proof of real impact ("this may be41slow") and (b) blindly piling on "optimizations" (caching, memoization,42denormalization) where there is no measured problem, which complicates the43code and creates a new class of bugs (stale cache, race condition) for a44nonexistent gain. Neither failure should occur:45461. For each finding where technically possible, confirm the impact by47 measurement: EXPLAIN ANALYZE for a SQL query, profiling (py-spy/cProfile)48 for a CPU hotspot, the real bundle size for the frontend, the output of49 existing k6 scenarios from `load-testing/` for the load characteristics of50 the API. A finding without a number is a hypothesis, not a finding; flag it51 explicitly as "not confirmed by measurement" and state what is needed to52 confirm it.532. Do not propose optimization where there is no proven problem. If code is54 "non-idiomatic" but is not on a hot path and does not consume noticeable55 resources — record it as cosmetic/low, not as a performance finding. Three56 identical lines are better than premature abstraction; the same principle57 applies to caches and memoization.583. Distinguish "theoretically suboptimal" from "really expensive at the59 current/expected data volume". An N+1 query on a table with 10 rows in the60 dev environment is not the same as an N+1 on a contacts/deals table with61 hundreds of thousands of rows in prod. Explicitly state at what data volume62 the finding becomes critical.634. If an optimization was already made earlier (check git log/comments) —64 check whether it later regressed (e.g. a cache was added but invalidation65 was forgotten when a neighboring module was refactored).665. State the status explicitly: "confirmed by measurement" / "plausible but67 not measured" / "not a problem at the current data volume" / "already68 optimized correctly".6970## METHODOLOGY: THREE INDEPENDENT PASSES7172Run the audit by three independent methods and do not let one pass substitute73for another — they have different blind spots.7475### PASS 1 — Instrumental analysis and profiling7677- **Backend (Python/FastAPI)**: enable SQL logging78 (echo=True/aiosqlalchemy debug) on the key scenarios and find N+1 queries79 and queries without LIMIT/pagination; where a DB connection is available —80 run EXPLAIN ANALYZE on the most frequent/heavy queries and record missing81 indexes (a seq scan where an index scan is expected); use py-spy/cProfile to82 profile CPU on suspect hot paths (webhook handlers, sync jobs,83 serialization of large responses).84- **Database**: pg_stat_statements (if enabled) for the top queries by total85 time and by number of calls; a list of tables without indexes on the columns86 used in WHERE/JOIN/ORDER BY (cross-check with each service's migration87 schema); table size and growth over time, if metrics are accessible.88- **Redis**: patterns of keys without TTL (risk of unbounded memory growth),89 KEYS/SCAN commands over the whole key space in the hot path, value size90 (serializing whole objects instead of the needed fields).91- **RabbitMQ**: prefetch/QoS configuration, queue depth, retry policies92 without backoff/DLQ.93- **Docker images**: dive or `docker history` on each built image — layer94 sizes, unused build tools and dev dependencies that ended up in the final95 image; compare against multi-stage build where it exists/is absent.96- **Frontend (the-frontend)**: build the production bundle and analyze it97 (`vite build --mode production` + rollup-plugin-visualizer/98 source-map-explorer, if wired in, or manual analysis of dist/ by chunk99 size); Lighthouse (or an analogue) on the key pages for LCP/TBT/bundle size100 metrics, if it is possible to bring up the frontend locally.101- **Load testing**: the repository already has k6 scenarios and reports in102 `load-testing/` (see `load-testing/ANALYSIS_GUIDE.md`, `load-testing/k6`,103 `load-testing/reports`). Read the existing reports — which bottlenecks were104 found earlier and not resolved; if the environment can be brought up — re-run105 the current scenarios and compare against the saved baseline reports.106- **Kubernetes/Helm**: checkov/kube-linter or a manual review of the charts107 for resources requests/limits (empty/missing — a risk of noisy neighbor and108 throttling; oversized — direct overspend of the infrastructure budget),109 liveness/readiness probe intervals (too-frequent probes = constant110 background load on N replicas), HPA configuration and its thresholds.111112### PASS 2 — Manual line-by-line code review113114Split the codebase into independent zones and review EACH (not diagonally,115not relying only on grep patterns):116117- Each backend service separately (gateway, all `*-service` directories in118 `services/`).119- Frontend / SPA (`the-frontend`).120- Background handlers, bots, and external-API integrations121 (telegram-bot-service, telegram-connector-service,122 whatsapp-personal-service, kommo-integration-service,123 verification-bot-service, ai-bot-service) — this is the code with the124 highest risk of constant background load (polling, syncs, long-polling), not125 just request-response on demand.126- Shared libraries (`libs/shared_auth`, `libs/shared_metrics`) — code that127 runs on EVERY request of EVERY service; even a small inefficiency here is128 multiplied by the number of services and replicas.129- Infrastructure configs (`helm/`, `docker-compose*.yml`, `deploy/`,130 `infrastructure/`).131132For each zone, look for (detailed checklist below) and for each finding133record: file:line, problem type, a quantitative impact estimate (or a "not134measured" mark), severity, status (see above).135136### PASS 3 — Architectural review137138Independently of the line-by-line review, assess whether the current139architecture can HOLD economy as load grows, not just be free of obvious140problems today:141142- A "chatty" inter-service architecture: how many sequential synchronous HTTP143 calls one user request makes through gateway → services → services (build144 the chain for the 2-3 most frequent scenarios: login, deals/leads list,145 sending a chat message). Every extra hop is latency and CPU/network,146 multiplied by traffic.147- Whether a fixed replica count is justified (in148 `docker-compose.microservices.yml` the gateway is brought up in 3 instances,149 etc.) — is there real load data justifying this number, or is it "just in150 case"? The same for analogous decisions in helm-values (replicaCount).151- Duplication of shared libraries (shared_auth, shared_metrics) across152 services instead of a single package — if a performance fix/optimization is153 made in one copy, does it propagate automatically to the rest, or does the154 patch have to be rolled out N times (the same risk as for security patches)?155- A general caching strategy: does one even exist as a deliberate decision156 (what is cached, at what level, with what invalidation), or is a cache added157 pinpoint and unsystematically wherever someone once noticed a slowdown?158- Combining OLTP load (transactional services) and heavy analytics (Superset,159 analytics-service) on the same DB/instance — contention for resources.160- Presence of a process: is load testing (k6 in `load-testing/`) run regularly161 or one-off; is there a performance budget for the frontend bundle and API162 latency, enforced in CI rather than only "by feel"?163164## DETAILED CATEGORY CHECKLIST1651661. **Async backend: blocking calls in the event loop** — synchronous HTTP167 clients (requests, etc.) instead of httpx.AsyncClient/aiohttp inside async168 handlers; synchronous I/O (opening files, time.sleep, synchronous DB169 drivers) inside `async def`; CPU-heavy operations (parsing large JSON/XML,170 encryption, image processing) on the event loop without171 ThreadPoolExecutor/ProcessPoolExecutor; sequential `await` where the calls172 are independent and could go in parallel via `asyncio.gather` (a typical173 pattern in the gateway when calling several services to assemble one174 response).1752. **Database (PostgreSQL)** — N+1 queries (a loop with a DB query inside where176 one JOIN/`selectinload`/`joinedload` would do); missing indexes on columns177 in WHERE/ORDER BY/JOIN, especially on foreign keys (user_id, tenant_id,178 integration_id) and multi-tenant filtering; `SELECT *`/full serialization179 where 2-3 fields are needed; list endpoints without pagination/LIMIT;180 connection pool size relative to the number of replicas and the PostgreSQL181 limit; long transactions with external HTTP calls inside (a categorically182 unacceptable pattern); repeated identical queries within one request-response183 cycle.1843. **Caching (Redis)** — keys without TTL; absence of a cache for expensive,185 frequently repeated, and rarely changing computations (dashboard aggregates,186 reference data, roles); cache stampede (no lock/single-flight on187 expiration); a cache without invalidation when the source data changes188 (record separately as a correctness problem, not only a perf one); KEYS/SCAN189 over the whole database in the hot path; storing large blobs instead of190 specialized storage.1914. **Inter-service communication (HTTP)** — absence of timeouts on outbound192 requests; absence of retry with exponential backoff (or retry without193 backoff — a thundering herd during a partial incident); duplicate calls to194 one service instead of a batched call; full forwarding of heavy payloads195 where only part of the data is needed.1965. **Queues (RabbitMQ) and background handlers** — prefetch/QoS (too large197 overloads the consumer, too small underuses parallelism); poison message198 without DLQ; external-API polling frequency (kommo-integration-service,199 telegram-connector-service, whatsapp-personal-service) relative to the real200 need, batch size, rate-limit handling (429/retries).2016. **Serialization and payload size** — Pydantic models returning202 significantly more fields than are actually used; logging large203 objects/payloads in full in the hot path; absence of compression204 (gzip/brotli) on the gateway for large JSON responses.2057. **Frontend (React/Vite/TS)** — production bundle size and absence of206 code-splitting/lazy-loading for rarely used routes; unoptimized207 images/static assets; excessive re-renders on large lists/tables208 (leads/deals) — absence of virtualization, new objects/callbacks in render209 without memo where the profiler clearly shows a hotspot (do not add210 memo/useCallback everywhere "just in case" — that also costs resources211 without a measured benefit); waterfall data loading instead of parallel;212 too-frequent polling where WebSocket/SSE would be more appropriate, or a213 WebSocket with excessive reconnect/heartbeat.2148. **Docker images** — final image size per Dockerfile (services/*,215 the-frontend); absence of multi-stage build where build dependencies end up216 in the final layer; an oversized base image (full OS instead of217 slim/alpine/distroless), if that does not create compatibility problems.2189. **Kubernetes/Helm** — resources requests/limits: missing (noisy neighbor,219 OOM-kill) and, at the same time, oversized "with a margin" without a basis220 in real consumption; liveness/readiness/startup probe intervals/timeouts on221 a large number of replicas; replicaCount and HPA thresholds — are they222 justified by numbers; init containers and pod startup logic — do they block223 readiness longer than necessary?22410. **Observability as a source of overhead** — metric cardinality225 (shared_metrics): high-cardinality labels (user_id, request_id as a label226 instead of a value); trace sampling frequency/volume; logging volume and227 level in prod (DEBUG logs "for convenience"); synchronous sending of228 metrics/traces in the hot path instead of batching/async sending.22911. **Algorithmic efficiency and data structures** — quadratic and230 worse-complexity operations over collections that will become a bottleneck231 at real data volumes (leads/contacts/chat-message lists grow over time);232 repeated parsing/recomputation of the same data within one request;233 unnecessary deep copying of large structures; absence of batching for bulk234 operations (leads import, syncs with external CRMs) where the operation235 volume is regularly large.23612. **Load testing and performance budgets** — currency of the k6 scenarios237 (load-testing/k6) relative to the current API contracts; discrepancy238 between the bottlenecks documented in load-testing/reports and239 load-testing/ANALYSIS_GUIDE.md and the current state of the code (are they240 actually fixed, or did the report remain un-updated — "fixed on paper");241 presence or absence of recorded performance budgets in CI (maximum bundle242 size, maximum p95 latency) — without such a gate, performance regressions243 slip into prod unnoticed.244245## EDGE CASES OFTEN MISSED246247- "Runs fast on dev data" — the problem shows only at real customer data248 volumes (thousands of leads, tens of thousands of chat messages); always249 estimate the expected growth.250- Debug conveniences forgotten in prod: verbose logging, disabled response251 compression, disabled cache "to make debugging easier" — and not turned back252 on.253- Health/readiness probes that hit the DB or external services on every254 N-second check, multiplied by the number of replicas — in total a noticeable255 background load on the DB with no business value.256- Several independent services polling the same external API redundantly257 instead of a shared cache/single synchronization point.258- Retry logic without backoff, amplifying load precisely at the moment of a259 partial incident (when resources are already scarce).260- Heavy analytical queries (Superset/analytics-service) running on the same261 DB/instance as the transactional load, during CRM peak load hours.262- "Optimization for optimization's sake": a cache/memoization/denormalization263 added without a measured problem — increases the complexity and volume of264 code that must be maintained and that itself consumes resources (cache265 memory, synchronization), without a proven benefit. Record such findings266 too — propose simplification.267- Configuration differences between environments (dev/staging/prod) in268 docker-compose/helm-values — an optimization made for one environment may be269 absent in another.270- Feature flags forgotten after experiments, doubling the work (writing to the271 old and the new system at once "during the migration", which finished long272 ago).273274## REPORT FORMAT2752761. Executive summary (for leadership, no technical jargon): what consumes277 resources most noticeably, what can be optimized without risk to278 functionality first, the approximate effect (in terms of279 latency/load/infrastructure resources).2802. KPI table: number of findings by severity (critical/high/medium/low),281 number of findings confirmed by measurement vs "plausible but not282 measured"; the approximate total resource savings from eliminating the283 critical findings, if it can be estimated.2843. If this is a re-audit — a comparison table "previous-report/load-testing285 item → current state (file:line) → status (not fixed / on paper /286 selectively / fixed)".2874. A "fixed but not working" section separately (e.g. an index was added in the288 migration, but the query still does a seq scan due to a type/function289 mismatch in WHERE).2905. Full list of findings tied to file:line, with a quantitative impact estimate291 (or an explicit "not measured" mark and what is needed to measure it),292 severity, and a concrete remediation recommendation (not "optimize the293 query", but "add an index on (tenant_id, created_at)", "replace the N+1 with294 selectinload", "move the external API call out of the transaction body").2956. A "what was done well" section — efficient patterns in the codebase worth296 replicating to other services rather than redoing.2977. Action plan by timeframe: quick pinpoint fixes without regression risk298 (indexes, timeouts, fixing N+1) — first; changes requiring testing under299 load — second; architectural decisions (rethinking the caching strategy,300 reducing the number of inter-service hops, a scaling plan) — as301 leadership/team-lead-level decisions.3028. A "methodology and coverage limitations" section — which tools and303 measurements were used, which services/zones were NOT profiled or loaded and304 why (no access to prod metrics, no ability to bring up the environment,305 etc.), so the absence of findings in an uncovered zone does not read as306 "everything there is optimal".307308## FINDING FORMATTING RULES309310For each finding, the following are mandatory:311312- The file path and line number (or range).313- The problem name and category (see the checklist above).314- A quantitative impact estimate: measured (number of DB queries, EXPLAIN315 ANALYZE output, profiling time, bundle/image size in MB, p50/p95 latency) or316 explicitly marked as an unmeasured estimate with justification for why it is317 likely.318- The condition under which the problem becomes critical (data volume, number319 of concurrent users, call frequency) — if it does not hold today but will320 hold as things grow, state it explicitly; do not under- or over-state the321 urgency.322- Severity with justification (what share of traffic/data is affected, which323 resource is consumed: CPU, RAM, network traffic, number of DB connections,324 infrastructure cost).325- Status relative to the previous audit/load-testing report, if applicable.326- A remediation recommendation — concrete and preserving the current327 functionality (the audit should not propose changing the system's behavior,328 only the efficiency of its implementation).329330## RUNNING THE AUDIT (practical instructions)3313321. Determine the scope: list all backend services (services/*), the frontend333 (the-frontend), shared libraries (libs/*), background bots/connectors,334 infrastructure configs (helm/, docker-compose*.yml, deploy/,335 infrastructure/), existing load tests (load-testing/).3362. Read the existing load-testing artifacts (load-testing/ANALYSIS_GUIDE.md,337 load-testing/reports) BEFORE starting the manual review — it is a ready338 source of already known bottlenecks; don't duplicate work, just check339 whether they are resolved.3403. Run the available tools of PASS 1 on each service/image/chart where possible341 in the current environment; save the raw output for report appendices.3424. Split the manual review of PASS 2 into independent chunks (by service/zone)343 — if the Agent tool is available, launch several independent subagents on344 different zones in parallel (in foreground, if the result is needed345 immediately in this dialogue), so as not to miss volume and not to let one346 agent "cut corners" across the whole codebase at once.3475. Perform the architectural review of PASS 3 separately, independently of the348 PASS 2 results.3496. Consolidate all three passes into a single report per the format above,350 remove duplicates, but do not merge findings of different natures (a tool351 found a suspicious pattern ≠ manual review confirmed real impact — record352 both facts if both exist, with the corresponding confirmation status).3537. If this is a re-audit — be sure to re-verify EACH item of the previous354 report and each finding from load-testing/reports against the current state355 of the code, rather than relying on the status claimed by the team.3568. Explicitly state which checks were NOT performed (no access to prod357 metrics/pg_stat_statements, no ability to bring up the environment for358 profiling or a k6 run, no data on real customer data volumes) — this is part359 of an honest report, not its weakness.3609. No recommendation should change the observable behavior/functionality of the361 system — only the efficiency of the implementation. If an optimization362 inevitably requires a behavior change (e.g. tightening default pagination) —363 note this separately and explicitly.364365This is an audit, not implementation: the developer makes the changes based on366the report, not you within this skill.367