2026 – now

Angular lead developer, Uzinfocom

Angular 21, zoneless, Signals, PrimeNG 21, Tailwind CSS 4, Transloco, OpenAPI, Node test runner

A control panel and live API docs for the integration layer of the national school system

Context

The national school information system exchanges data with other government and enterprise services through an integration API: student records, enrolment history, organisation data. Partner organisations get accounts, endpoints and limits; every call is logged. The team that operates this needed one place to manage access, watch traffic and let partners see how to call each endpoint. I built that panel from scratch at Uzinfocom, starting in May 2026, and maintain it.

The problem

Before the panel, managing partners meant editing data by hand and reading logs on the server. Partners had no documentation they could try against the real API. And the first version of the panel, built on a PrimeNG admin template, shipped 2 MB of JavaScript before the login form appeared.

Constraints

Government operators and partner developers in Uzbek Latin, Uzbek Cyrillic and Russian. A backend with an unusual contract: every call is a POST, reads included, parameters in the query string, every response wrapped in one envelope. The panel had to stay strict and predictable so a small team could extend it screen by screen.

What I did

Built the application on Angular 21 with zoneless change detection, Signals for state and standalone components throughout, PrimeNG 21 for tables, dialogs and forms, Tailwind CSS 4 for layout. Every screen follows one pattern: a list component with signals for loading, saving and table state, a shared table wrapper that owns paginator, loading, empty and error states, a sibling form dialog on reactive forms that emits saved, and a @Confirmable decorator that guards destructive actions behind a translated confirm dialog. Wrapped the backend's all-POST contract in typed API services, one per entity, with a single response envelope unwrapped in one place and a typed error interceptor that normalises every backend error shape into one message and logs the user out on 401.

Screens: roles and permissions, users and their roles, organisations, API endpoints, endpoint logs, per-endpoint rate limits, per-user IP allow rules, and the interactive API documentation. Everything is translated with Transloco; keys are extracted and checked by script, so an untranslated string fails review rather than shipping.

Wrote the API docs generator: a Node script reads the backend's OpenAPI spec and emits the documentation data the panel renders, grouped by controller, with request bodies mapped to form, raw JSON or file upload depending on the schema and example values prefilled for well-known parameters. The mapping is pure code with 161 tests on Node's built-in test runner, so a backend contract change is a regeneration and a diff, not an afternoon of editing. It currently covers 20 controllers and 144 endpoints.

Ran a performance pass and wrote it up as a plan with gates: self-hosted fonts and a sized logo for layout stability, lazy boundaries for the shell, dashboard and not-found routes, theme presets loaded on demand, the template's demo code excluded from the production build by file replacement, and a bundle-size gate that fails the build when a route grows past its budget.

Partner and enterprise services
Integration API of the school system
Control panel: access, endpoints, limits, logs
OpenAPI spec → generated interactive docs
Where the panel sits. Partners call the integration API; operators run it from the panel; docs are generated from the same OpenAPI spec the API publishes.

Build and release

The panel ships as a static single-page app. npm run build:prod first stamps app-version.json with the package version, an auto-incremented build number, the short commit hash, branch and timestamp, so any running build can be identified exactly. Angular's application builder then produces the production bundle with two file replacements: the production environment, and a demo route configuration that drops the template's demo pages from the bundle entirely. Budgets fail the build if the initial bundle passes 700 kB or any component stylesheet passes 4 kB; npm run build:analyze emits stats and runs the bundle report, which has its own unit tests. Before a release, translation keys are extracted and checked by script, and the documentation data is regenerated from the OpenAPI spec with npm run docs:generate whenever the backend contract changes. Hosting is any static server with a single rewrite to index.html; the repository carries that config for Vercel-style hosts.

What happened

Initial bundle Before After Change
Raw 2.03 MB 592.88 kB −70.8%
gzip 477.1 kB 158.22 kB −66.8%
Brotli 384.5 kB 137.61 kB −64.2%
Files 17 11 −35.3%

Operators manage partners, limits and IP rules from one interface and read request logs there instead of on the server. Partner developers get documentation that is generated from the spec, so it is never out of date, and can see exactly what each of the 144 endpoints expects. The bundle gate keeps the initial load from creeping back up.