root@construct:~/projects/tjes$
<-- back to /projects

TJ-ES Platform

Management platform prototype for the Espírito Santo Court of Justice

PythonFlaskVueBootstrapPostgreSQLDocker

>Context

The Tribunal de Justiça do Espírito Santo (the state court of Espírito Santo, Brazil) runs 20 modernization projects under the Innovation in the Service of Justice program, split across tracks and teams. They started separately but share expensive pieces: authentication, roles and audit, contracts, assets and the look of the screens. If each team builds its own, the same piece gets built several times, and the court's IT inherits all of it at the end.

I'm a software engineer, on a research grant, in the program since 01/10/2026; the first proof of concept of the shared structure came out on 19/09, before the official start. Since 21/10 I work across all tracks: I take care of the design system and the architecture standards for the 20 projects and help the teams connect the pieces.

In the Engineering track I keep building Project 19 (works, contracts and services management), for the court's Engineering Department, and I'm also on Project 20 (real-estate technical registry). I also wrote the technical access proposal for the court's IT: how the program works with no new accounts, no production access and no real data outside the court.

>High-level design

It will run on the court's infrastructure, on the standard the court's IT set on 06/10: Python 3 with Flask, Vue with Bootstrap, PostgreSQL and Docker. No one in the program has production access. Today P19 runs in local development: Flask listens on a port and Vite forwards /api calls to it.

A request leaves the browser, goes through the Vue 3 front end and reaches the Flask API over REST. The route only translates HTTP into a use case, and the composition root picks which adapter serves each port. The budget comes in through the budget port, with two adapters: a client for the budgeting system's API, tested against a fake transport and not yet run against the real system, and a sample file. Sign-in lives in the access context, which has no code yet. State goes to PostgreSQL; until then an in-memory repository fills the same port. There is no queue or job: importing a budget is a synchronous call.

Every push to the program's repository, with fictitious data only, runs the same check: ruff, mypy, xenon and pytest with coverage on the back end; vue-tsc, ESLint, Vitest and the build on the front end and the design system. The code is copied to the court's GitLab, where I left a pipeline with that check, not run yet. Only the court's IT approves and releases to production.

Hover or focus a piece: it lights up with its links.
who uses itProgram · fictitious dataState court (TJES)external servicesProduction (court IT only)2 Design system1 Court employees5 Authentication3 Program repo9 Flask API (P19)6 Vue front end (P19)4 Architecture suite7 Other projects12 Budgeting system8 Court GitLab11 PostgreSQL10 Court IT approval
12 pieces11 links4 areas

Components

  • Shared design system :: A Vue 3 package on Bootstrap 5.3, with tokens following IBM's Carbon method and the brand of the court's portal, that the screens of P19 and the other projects are built from.
  • Vue front end per project :: A Vue 3 and Vite SPA that builds screens only from design system components and calls the project's API over REST.
  • Flask API by context :: A Python 3.13 back end organized in seven contexts, with domain and use cases free of framework, database and I/O, and HTTP, database and external-system adapters at the edge.
  • Budget port :: Brings the budget from the budgeting system over its API or from a sample file; configuration picks the adapter, and domain and use cases stay the same.
  • Persistence :: PostgreSQL, the database in the IT standard; today an in-memory repository serves the same port.
  • Architecture suite :: import-linter contracts and dependency-cruiser rules run in make check on every push and fail whoever breaks the dependency rule.
  • Delivery flow :: Code in the program's repository, with fictitious data only, copied to the court's GitLab; approval and release to production by the court's IT only.

>Trade-offs

Flask, Vue, Bootstrap and PostgreSQL, the court IT standard.

Alternative rejected: React and Node with TypeScript, the stack of the first proof of concept, from 19/09.

Why: The court's IT presented its standard on 06/10, and it maintains the code after the program ends. The old decision is recorded as superseded.

Architecture rules checked by tests.

Alternative rejected: A rule written in a document and enforced in code review.

Why: With several teams on one standard, the rule has to fail on its own. Swapping the sample file for the real API, or memory for PostgreSQL, becomes swapping one adapter at the root; domain and use cases stay the same.

Design system accepted as a prototype before it becomes Vue components.

Alternative rejected: Write the Vue components right away and adjust later.

Why: I asked the coordination and the teams for feedback before fixing how it is used: what each project is missing and what they would change. A component only enters the package with a test.

>Highlights

  • >Access proposal with 4 commitments: no new court accounts for the new solutions, zero production access, no real data outside the court and all code copied to the court's GitLab.
  • >4 architecture contracts on the back end and 10 rules on the front end; on the back end, complexity above 5, more than 4 parameters or coverage below 90% fail the check.
  • >Design system prototype with 6 components documented in Usage, Style, Code and Accessibility, light and dark themes and 3 clickable P19 screens.

>Fun facts

  • *On 19/09, 12 days before the official start, I told the squad group I had a free morning and had already put together a small PoC with a shared structure.
  • *The design system prototype opens with no internet: fonts, icons and Bootstrap ship inside the package, no CDN.
  • *In P19 the domain can't even import os, json or logging: the io-free-domain contract rejects any I/O.
  • *Code is 100% English and screens are Portuguese: a glossary in an ADR maps orçamento to budget, medição to measurement and diário de obra to site_diary.
TJ-ES Platform | The Broad Way | Kinho.dev