Engineering practice certification-compliance

From manual Excel to built-in analytics: 356 hours of reporting for a B2B platform

Monthly Excel roll-up moved into the platform: a statistics grouper, geo-filters with DaData postcode normalization, a yearly chart, a classification reference.

356h delivered
From manual Excel to built-in analytics: 356 hours

Every month the client’s staff exported raw data out of the platform and assembled the statistics in Excel by hand. That’s half an operator’s salary, and everyone rolls it up their own way. We moved the work inside the platform across five specs and 356 hours. The hardest part was not the charts and not the filters. It was reference-data discipline: until a dozen spellings of one technical regulation collapse into a single class, automatic grouping returns garbage instead of a report.

Snapshot

End-client sector product certification, B2B market analytics
End client Certificate Analytics
Engagement retainer — a stream of numbered specs for analytics functionality
Project type moving a manual Excel roll-up into the B2B platform’s built-in analytics
Work done query-builder module, statistics grouper, geo-filters with address parsing, shared filter layer, yearly chart with master reference
Project date Q4 2021 — main block closed by 2023, yearly chart still maintained today
Effort 356 hours by spec (agreed/billed)
Team Anton Hersun (project manager) and the analytics-panel developer, who has run this track from day one through today
Tech stack Laravel · Sencha 6 grid · core tabular-data builder · MariaDB aggregations · child compute server
Delivered query builder (65h), statistics grouper (90h), geo-filters and address parsing (100h), shared-report filters + news (16h), yearly chart with master reference (85h)

The problem

The client’s staff had a settled Excel practice: once a period, export raw data out of the platform, drop it into fixed-structure files, and tally the statistics. How many documents each certification body issued, how they split across technical regulations and product classes. The platform gave them none of this. The statistics spec said so outright: “From the data we export, we build the statistics for the period by hand in Excel.”

The client placed specs in pieces. First a grouper over simple metrics, then geo-filters with address parsing, then shared-report filters with news, and at the end a yearly chart with a master classification reference.

Why this is hard. The weak spot in reports like these is the reference data. Records arrive from registries in a jumble: one technical regulation is written a dozen ways (“TR CU 021/2011”, “on food products”, “TR CU 022/2011 re labeling”). The Excel operator folds them into a single row, “Food products”, because they count by hand and hold the mapping in their head. To the database these are different values, and automatic grouping over them falls apart. Addresses have the same trouble: in the registries they sit any way at all, one city written in several styles, and some documents carry no postcode. So the center of this case is not charts and not filters. It’s two duller things: a master classification reference and address normalization. Without them the reports would have stayed manual.

How we did it

1. Built on the core tabular-data builder, instead of writing a separate reporting engine.
The builder is part of the platform’s original core (see the “Original platform build” case): an operator sets columns and groupings right in the interface. Every analytics spec grew out of it. We added new field groups (technical regulation, declaration-object type, geography) rather than writing separate code for each report. That made each next spec cheaper than the one before.

2. Statistics grouper (90h): the first step out of Excel and into the platform.
The platform gained an “Analytics” section with a “grouper” menu and report types such as “TR CU declarations, by applicant”. We showed the first working report a week after the start, then opened the module to all users two weeks later. Along the way the grouping logic had to be reworked, 30 hours over the spec, and those stayed on our side. From that point the monthly roll-up stopped living in Excel files.

3. Geo-filters and address parsing (100h): where sorting by address would not collapse.
The client wanted to filter reports by date, region, and city. A plain text filter on the address caught any partial match, like %like% in Excel, and returned garbage: addresses in the source database are written however they land. We parsed the address by postcode instead, through the Russian Post postcode database and the DaData service, fractions of a kopeck per request. The postcode gives a stable key where the text spelling drifts. Documents with no postcode are still searched the old way, by text. A familiar story for us: an external source hands over dirty data, and the normalization costs more than the filter itself.

4. Shared-report filters and news (16h): in 3 days.
Individual reports had configurable filters. The shared one did not, since a single filter set covers every table there. The client asked to add filters by federal district, applicant, registration number, and TR CU, plus a news block on the front page. The difficulty was not the interface but the underlying join table: some filters needed extra code, because the “one field, one table in search” scheme did not cover those cases. We assembled it, tested with the developer, and delivered 3 days after sign-off.

5. Yearly document chart and master reference (85h): we talked the client out of an outside system.
The client wanted yearly charts over declarations and certificates, and here the road forked. We could stand up Grafana: we deployed it on a separate server to check the idea and built the first simple charts, which would have run around 70–80 hours. Or we could write our own document-analytics module inside the platform, about 100 hours. We did not propose Grafana. Our own competence in it at the time was not enough to guarantee the result and the dates. The honest choice was to build the module inside the existing analytics, where we own everything. That’s what we agreed on.

Technically the task came down to load: yearly aggregations over the whole dataset put the main server on its knees. We stood up a child server, set up data forwarding to it and pre-processing. Scripts prepare the tables so the queries run at an acceptable speed. In parallel we closed the original reference-data problem that started all of this: the master classification reference. An administrator sets up a mapping table, “source field from the database to a rolled-up class”, and a dozen wordings about food products (029/2012, 021/2011, 022/2011, and the rest) collapse into a single class, “Food products”. Without this reference, grouping over real data comes apart. We closed the spec over the hour budget. The overrun stayed on our side, not on the client’s account.

6. Query-builder module (65h): built to spec, the concept never came together for the client.
The query builder works as a query constructor: pick products by combined TR CU / HS code with multi-select. We delivered the forms and a base of around 26,000 positions on time. Then came the question of populating it, and the client wrote plainly: “How to fill it, we’re racking our brains, almost no ideas.” No use for the concept ever surfaced. We proposed closing the spec rather than leaving it in limbo. The builder itself stayed in the system and is reused in other reports. The module was delivered to spec. A product idea for it never crystallized on the client’s side.

Results

Metric Value
Hours by spec 356 hours (65 + 90 + 100 + 16 + 85)
Specs in the analytics block 5 numbered orders
What it replaced the staff’s manual monthly Excel roll-up
Architectural reuse every spec sits on the core tabular-data builder
Key move master classification reference + address normalization, without which analytics over real data fell apart

Built-in analytics closed the old manual cycle. The monthly roll-up is now assembled by the grouper, not by a person in Excel. Geo-filters work on dirty addresses through postcode normalization, the shared filter layer covers every table, and the yearly chart is computed on the child server without touching the main one. The master reference turns the jumble of registry wordings into meaningful classes. The chart is alive and maintained by the same developer to this day: in early 2026 the client wrote that the chart “won’t show 2026”, and we fixed it under the retainer.

Process and timeline

Stage Period Outcome
Query-builder module Q4 2021 — Feb 2022 65h — query constructor; the populating concept never came together for the client
Statistics grouper Dec 2021 90h — first report in a week, open to all in two, +30h of rework over the spec
Geo-filters and address parsing Jan 2022 100h — date/region/city filter, address normalization by postcode + DaData
Shared-report filters + news Jul 2022 16h — federal district, applicant, registration number, TR CU; built in 3 days
Yearly chart with master reference Feb — Apr 2023 85h — own module instead of Grafana, child server, master reference; closed over budget on our dime

What the client chose not to do, we logged too: a yearly-report upgrade (mid-2023) stalled at the estimate stage, no formal spec appeared. A multi-select of several federal districts in the shared report (December 2023) was costed at 10 hours, and the client deferred it.

Team

  • Anton Hersun, Xaver Pro — project manager: master-reference requirements, filter formalization, the “Grafana or own module” fork, the child compute-server infrastructure
  • analytics-panel developer — server and client sides of the analytics modules. The tabular-data builder, grouper, query builder, and yearly chart were all written within one track that has run since 2021. Any module written years ago is extended by the same person: the yearly chart is fixed to this day.

Screenshots and materials

To be added in a separate pass.

If your reports are still assembled by hand in Excel from CRM or platform exports, send us the three most common types. We’ll tell you what it takes to move them inside the system, and where the first half-salary gets freed up. The review costs nothing.

Move your reports into the system →


Scroll to Top