Skip to content
Tanveer Hoque

Open to work

Tanveer Hoque

Backend Engineer · Civica · Cardiff

Backend engineer: Java and Spring Boot finance microservices, and the discipline that keeps them fast, correct and cheap to run

I build the backend services that finance runs on, and I measure them before I claim anything. Four years of production Java and Spring Boot: one critical finance API taken from 99 seconds to under one by fixing the query rather than hiding it behind a cache, and a payment flow moved onto events over RabbitMQ so a slow downstream call no longer holds a request open. On the side, a Rust service that puts nine model providers behind one API.

caseIn progress

agent-platform

One OpenAI-compatible endpoint in front of every model, hosted or running on the desk.

7 hosted + 2 local
Upstreams behind one API
0 lines
Provider-specific code in the client
99s → 0.9s
API latency

One critical finance endpoint. The slow query was restructured rather than hidden behind a cache.

4yrs
In production

Java and Spring Boot, finance. Where the operational habits come from.

9
Model providers behind one API

Seven hosted services and two running on the machine itself. The application never learns which one answered.

−68%
Agent cost

The same four tasks, sent to the cheapest model that could still do them. Checked by running the results, not by asking the agents how they did.

01

What I build with

The tools in production now. Depth for the rest is one disclosure away.

  • Java4 yrs

    Languages

    Primary language: Spring Boot services, JPA, tests.

  • Spring Boot4 yrs

    Frameworks

    Finance microservices, event listeners, scheduled work.

  • PostgreSQL4 yrs

    Data & messaging

    Finance schemas, query tuning, index work.

  • Jenkins4 yrs

    Delivery & ops

    CI/CD for pre-release and production pipelines, release ownership.

  • TypeScript4 yrs

    Languages

    Node services and every front end since 2022.

  • SQL4 yrs

    Languages

    PostgreSQL: query plans, indexes, Liquibase migrations.

The rest of the stack

Read it · Ships production code · Sets the standard

Languages

What the services are written in, and what the scripts around them are written in.

  • JavaScript5 yrs · current
  • Rust1 yrs · current

    agent-platform: the server, its desktop client, and the LLM proxy inside it.

  • Python6 yrs · current

    Django and Flask, then FastAPI; agent-platform’s model-training worker and the tooling around it.

  • Bash4 yrs · current

    Build, push, restart: the automation around a deploy.

  • C++2 yrs · last used 2019

    Algorithms and contest work at university.

  • Kotlin2 yrs · current

    A JetBrains IDE plugin, an Android client and a launcher, all shipped.

  • Dart5 yrs · last used 2026

    Flutter apps since 2021, most recently portal_warp and a shared UI kit.

  • C#3 yrs · current

    The .NET 8 Kestrel host inside Portal Remote, and desktop tools before it.

  • Go1 yrs · last used 2025

    One service. Read comfortably, written rarely.

Frameworks

Backend first. The front-end entries are there because the same person shipped both ends of these systems.

  • Spring Batch4 yrs · current

    Payroll estimation and transaction creation jobs.

  • JPA / Hibernate4 yrs · current

    Where the 99-second query lived.

  • Node.js4 yrs · current
  • NestJS2 yrs · current
  • FastAPI2 yrs · last used 2026

    The first agent-platform server, before it was rewritten in Rust.

  • Axum / Tokio1 yrs · current

    Streaming responses and an OpenAI-compatible surface on one process.

  • GraphQL3 yrs · current

    The gateway API at work: one client call fans out across several Spring Boot microservices.

  • React4 yrs · current
  • Next.js3 yrs · current
  • Astro1 yrs · current

    This site, and the two others that share its backend.

  • Tauri2 yrs · current

    Five desktop applications shipped with installers, auto-update and signed release manifests.

  • Svelte / SvelteKit2 yrs · current

    Portal Desktop on Svelte 5, plus logs-explorer and wingbot.

  • Flutter5 yrs · last used 2026

    Mobile apps and a shared component kit.

  • .NET 81 yrs · current

    A self-contained Kestrel host that runs without .NET installed.

  • Jetpack Compose1 yrs · current
  • Android5 yrs · current

    The MSc dissertation app, and the phone half of Portal Remote.

  • Tailwind CSS3 yrs · current
  • Django1 yrs · last used 2019

    Personal projects only. FastAPI is the Python framework the current work uses.

  • Flask1 yrs · last used 2022

    Personal projects only, mostly Raspberry Pi services.

Data & messaging

Where the state lives and how it moves between services.

  • RabbitMQ3 yrs · current

    Payment flow: queues, retries, dead letters.

  • Liquibase4 yrs · current
  • MongoDB2 yrs · current
  • SQLite1 yrs · current

    agent-platform’s store, through sqlx.

  • Flyway1 yrs · current

    Migrations in the Spring Boot 4 work, as Liquibase is in the finance services.

  • TypeORM1 yrs · last used 2025
  • Firebase1 yrs · last used 2021

    Auth and storage behind the MSc dissertation app.

Delivery & operations

Delivery & ops

Getting it out, and knowing what it did once it was out.

  • Docker4 yrs · current
  • Kubernetes3 yrs · current

    Daily on GCP to develop and test; own scripts reduce image build and scaling to one command.

  • Google Cloud3 yrs · current
  • Vercel2 yrs · current
  • GitHub Actions3 yrs · current
  • Tauri updater & code signing1 yrs · current

    Seven installers per release across three platforms, updating themselves from a signed manifest.

  • npm publishing1 yrs · current

    @tanvoid0/bot-client, released through a CI pipeline that gates it.

Testing & tooling

The parts that decide whether the rest of it can be changed safely.

  • JUnit4 yrs · current
  • Git6 yrs · current
  • Jira4 yrs · current

    Scrum and Kanban, estimation, technical-debt stories.

  • Testcontainers1 yrs · current

    A real PostgreSQL under the integration tests rather than an in-memory stand-in.

  • Spring Boot Test / @WebMvcTest4 yrs · current
  • pnpm2 yrs · current

    Workspaces: one backend package consumed by four sites.

  • IntelliJ IDEA6 yrs · current

    Enough of the platform to publish a plugin to the JetBrains Marketplace.

  • Maven4 yrs · current

    The build for every service at work: multi-module reactor, dependency management, the pipeline that consumes it.

  • Jest3 yrs · current

    Unit and integration suites for the Node and TypeScript work, gating releases in CI.

AI, models & agents

Models & agents

Two different things, kept apart on purpose: models a service of mine calls at runtime, and the assistants I write code with. Both are listed because a claim about either is checkable against a repository.

  • Claude Code1 yrs · current

    Daily driver. This site and the shared backend behind it were built through it.

  • Ollama1 yrs · current

    Local models behind agent-platform, reached from inside Docker. No key, no egress.

  • OpenAI-compatible APIs1 yrs · current

    The /v1 surface agent-platform serves, so any existing client points at it unchanged.

  • Cursor2 yrs · current
  • Gemini API1 yrs · current

    Document generation and assessment across three services.

  • Anthropic API1 yrs · current

    Wrapped behind bot-client alongside four other providers.

  • LM Studio1 yrs · current
  • LLM evaluation harnesses1 yrs · current

    Benchmark sets replayed against real inputs: 395 sessions for the cost gate, a scored corpus for the screener.

02

Also shipped

The other public cases. Every card opens the write-up.

Side project

Live

portfolio-core

One backend, several portfolio sites that look nothing like each other.

Open source

Live

Portal Desktop

A desktop client for the agent platform: terminal, repositories and agent workspace in one window.

03

One system, properly

What the finance API was built against, what each decision cost, and what changed.

TopologyOne endpoint over nine model providers
  • client
  • service
  • store
  • external

Context

An agent worth using talks to several model providers, and each arrives with its own SDK, its own auth and its own idea of what a streamed response looks like. The local runtimes are worse: the code that reaches Ollama on a laptop is not the code that reaches it from inside a container, so the thing that works while developing is not the thing that ships. The service began as a FastAPI server and had to end up somewhere it could be embedded in a desktop application, serve other API clients as a real server, and deploy to the cloud with no desktop client at all.

Constraints

  • Three requirements in conflict: ship embedded with a desktop app, serve other API clients, and deploy to the cloud with no client. The third rules out one binary carrying both the GUI and the API.
  • No flag day. The Python server had to keep answering everything that had not moved, and the migration had to be abandonable at any point without losing what had already landed.
  • Accepting a caller’s own provider key means accepting a base URL, and an arbitrary upstream URL is an SSRF primitive.
  • Local runtimes advertise themselves on 127.0.0.1, which inside a container means the container.
  • Clients already written against OpenAI must point at it and need no branch per provider.

Results

Upstreams behind one endpoint
an SDK, an auth scheme and a stream shape per provider9, seven hosted and two local
Provider-specific code in the client
one path per providernone
A local model from inside a container
worked outside Docker onlythe same route as a hosted provider
Servers in the path
Rust in front of Python during the migrationone binary, the Python server deleted
Provider keys held by the gateway
required to call on a user’s behalfnone, the caller’s key is forwarded per request

Decisions

  1. 01

    Replace the Python server with a strangler, not a port.

    Trade-off

    Two servers live at once for the duration, and a rule that every migrated route be byte-identical to the one it replaced, which cost the freedom to improve anything while it ran.

    Why

    A rewrite that has to land all at once is a rewrite that can only fail all at once. Moving domains across a few at a time meant no flag day, and a migration that could be abandoned at any point without losing what had already landed. It ran 5 to 7 August 2026 and the Python server is now deleted.

  2. 02

    Override the byte-identical rule to finish, and write down what changed.

    Trade-off

    Four behaviours differ from the server that was replaced.

    Why

    The rule existed to stop two live servers diverging. With one server there is nothing to diverge from, so keeping it would have preserved bugs on purpose. The four are recorded as changed rather than quietly absorbed.

  3. 03

    Forward the caller’s provider key per request instead of storing one.

    Trade-off

    A header per request, and the server can spend no quota of its own on a caller’s behalf.

    Why

    A gateway that stores provider keys becomes the most valuable thing on the host. Forwarding removes the category rather than defending it.

  4. 04

    Constrain the base-URL override to a canonical host or an explicit allowlist, https only, never a raw IP.

    Trade-off

    A genuinely new upstream needs an allowlist entry rather than a header.

    Why

    Bring-your-own-key is only safe if bring-your-own-URL is not. Without the constraint the same feature is a way to make the gateway reach internal services on the caller’s behalf.

  5. 05

    Rewrite loopback addresses to the host once, at the boundary.

    Trade-off

    One more thing that is true at the edge and not visible in the call sites.

    Why

    Doing it per call site is how a local model becomes a route that only works when the process happens to be outside Docker. Doing it once makes a local runtime a supported upstream like any other.

StackRustAxumTokiosqlxSQLiteicedDockerOllamaLM StudioPythonFastAPI
04

Contact & access

The public page is the summary. The detailed record is released by an issued link, one recruiter at a time.

Direct line

Get in touch

For a role, a contract, or a question about anything on this page. Replies come from me, not from a form.

Based
Cardiff, United Kingdom
Work authorisation
Skilled Worker visa: currently authorised and working in the UK; a new employer needs a sponsor licence.
Notice period
One month
Get in touch

If your mail client does not open, write to tanvoid0@gmail.com.

CV

The same facts as this page, laid out the way an applicant tracking system reads them. Built from the public record at deploy time, so it cannot fall behind what the site says.

Open the CV

Opens as a document — print or save it as PDF from there. No phone number or postal address on it.

For recruiters & hiring teams

Detailed record access

The CV above is the summary. What a link adds is the part a CV has no room for: per-engagement technical detail, certificates, degree transcripts, and the phone number and postal address the public copy leaves off. Released to one recipient at a time.

  • Issued to one person or one company, and revocable at any time.
  • Scoped: a link releases only the sections it was issued for.
  • Expires, and can be limited to a number of views.
  • Optionally tied to the recipient’s email address, so a forwarded link is useless.
Request record

Already have a link? Open it directly; no account or sign-in is required. Opening it sets one strictly necessary cookie so the record stays open while you read it; nothing on these public pages sets any. See the privacy notice.