EC · Enrique Chyrnia / Legajo ← Home
Backend · Infra
Experience file · cover Exp. 001/EC ·

Backend and infrastructure for a platform in production

No internal material
CompanyMas Que Bien Service
RoleBackend developer
PeriodJanuary 2026 – present
Engagementemployee, under contract
Fronts3 (backend · registration · panel)
StackJava · Spring · Postgres · AWS

I\'m the person responsible for the backend and the infrastructure of a platform in production at Mas Que Bien Service: a user app, a professional app, and a panel for the internal team. What you won\'t find here is code, screenshots, real topology or internal product names — that belongs to the company. What\'s left is how I solved each thing.

What I actually did

I designed and built the backend architecture: separation by context, a database per module, the API entry layer, file storage, caching, external integrations behind abstractions, the technical documentation, infrastructure as code, and the cloud deployment.

Experience file · piece 01 of 06 Context
01What an operational platform needs

A platform with three faces — users, professionals, an internal team — needs a lot of pieces underneath: a modular backend, clear APIs, external integrations, files, business rules, an admin panel. And each piece has to change without breaking the rest.

My work covered the three fronts that hold that up: the backend and its infrastructure, provider registration, and the internal panel. In all three I worked the same way — the API contract first, validation on the server, and every decision written down with its reason.

Backend & infrastructureSeparation by context, a database per module, API entry layer, caching, and file storage.
Rules & integrationsBusiness logic validated on the server, and external providers behind abstraction layers.
Documentation & deploymentOpenAPI contracts, decisions written down, Terraform, Docker, tests, and deployment on AWS.
Experience file · piece 02 of 06 Front 1 · backend & cloud
02Modular backend and cloud infrastructure

Design and implementation

The problem. The platform had to split responsibilities, make deploys cheap, organise data by domain, and take on external providers without welding the core logic to any of them.

What I did. A modular backend with services separated by responsibility, a database per module, an API entry layer, caching, file storage, technical docs, and the infrastructure written as code.

Client interfaces User app Professional app Internal team API layer identity + routing Backend services Service A Service B Service C Data and files Outside and operations DataPostgreSQL CacheRedis Filesobject storage External APIs Observabilityand configuration separate responsibilities · one database per module Infrastructure as code (Terraform) · container deployment (Docker) · configuration per environment Redrawn and simplified. It does not represent the real topology of anyone's system.

Annex A · the platform, seen from far away.

How the backend is split

I split it by context, not by technical layer. Every context carries the same three folders: web with controllers and DTOs, which doesn't know the database exists; application with the use cases and the rules; infrastructure with JPA, storage and config. I copied the shape of the microservices we'd migrate to later, so the move would be mechanical.

File storage goes in through one interface. In production the files live in Amazon S3; on my machine I run MinIO in Docker against that same interface. Three config properties change and the code stays put. In the database I keep the file's key, never the bytes.

Context Port and adapters web controllers · DTOs · errors. no database here application use cases · rules · approval policy infrastructure persistence · adapters · configuration Depends inward storage interface one only, the implementation changes on my machine MinIO in the cloud the real service 3 config properties the code doesn't change between them

Annex B · one context up close, and the seam where the provider gets swapped.

The sheet I fill in before deploying

I don't call a deploy good until every box says where it comes from. The right-hand column is the one that costs work and the one that's worth it.

Check
Evidence
The image works in any environment
the Dockerfile doesn't pin the profile: whoever starts it decides
The port comes from the environment
one config line, with a default for development
Credentials and endpoints by variable
database, storage, integrations and admin — nothing in the repo
The health check stays open on purpose
integration test: it answers 200 with no credentials
The signed webhook gets in without a login
valid signature 200, anything else doesn't pass
The internal panel, closed
401 with no credentials · 200 with the right ones · 401 with the wrong ones
Pasted from the terminal
86 unit tests · 18 integration tests · 0 failures
three branches in parallel, merged in one go — the conflict I expected in the config never happened, and I still checked it by hand
How the services are laid out
Seven services, one doorSeven backend services, each running as its own ECS Fargate task and owning its database — all on a single RDS instance, so the isolation doesn't multiply the bill. Client, provider and staff apps come in through one gateway that checks the token and routes.
One role per serviceEvery service assumes its own IAM role with only the permissions it needs: most touch nothing outside their own data, and only the one that runs document checks reaches the vision and OCR services. If one is compromised, the blast radius stays inside it.
No keys in the repositorySecrets live in Secrets Manager and each task gets temporary credentials at runtime through STS. Configuration comes from the environment, so the same image runs in every environment without a rebuild.
Two regions, on purposeThe system runs in the cloud region closest to its users. Only the document-and-face checks cross to a second region, because the managed services they need aren't offered in the first one — about 150 ms round trip, paid by that call alone and not by the rest of the platform.
Matching by distance, and a price that stops moving

One of the services matches requests to nearby providers using geospatial queries in the database, and offers the job in waves: small batches, ordered by a scoring rule, each with a deadline to accept. When a request is confirmed the price, tax and commission are frozen into an immutable snapshot — a rate change tomorrow never rewrites what was already agreed. I took part in defining that structure and its flow.

Modular designREST APIsPorts and adaptersPer-module persistenceMigrationsConfig per environmentInfrastructure as codeCloud deployment

Java · Spring Boot — PostgreSQL · Flyway — Redis — object storage — Docker · Terraform · AWS — OpenAPI

Experience file · piece 03 of 06 Front 2 · registration
03Registration, documents and identity checks

APIs, states and files

The problem. A guided sign-up has to save progress, validate on the server, take files, and expose a contract clear enough for the frontend to move without asking.

What I did. The endpoints and the rules behind them: a draft that survives a closed tab, the required documents worked out from the professions the person picks, states with their history, uploads with type and size limits, and errors with stable codes instead of a generic 500. The screens were built by someone else on the team; the shared contract let us work in parallel.

Draft Submitted Verifying Approved· Sent back

Every jump is written down with who caused it and when. Nothing changes state without leaving a trace.

Identity, on the other side of a wall

Identity verification runs with an external provider, and the platform talks to it through one interface. The provider's answer comes in by webhook, signed; if the signature doesn't check out, the request doesn't get in. What the provider returns is copied into our own storage in two steps, so a half-finished copy rolls back instead of leaving a record pointing at nothing.

Phone numbers are normalised before they're stored, ages are validated on the server, and duplicate emails come back as a business error with its own code — not as a crash.

State modellingServer-side validationUpload and validationDrafts with expiryOpenAPI contractsSigned webhooksTwo-phase copy with rollbackError catalogue

Java · Spring Boot — PostgreSQL — object storage — OpenAPI — Testcontainers

Experience file · piece 04 of 06 Front 3 · internal panel
04The panel the internal team works in

Queues, roles and auditing

The problem. A platform with users and professionals generates internal work: records and documents somebody has to review, a catalogue to keep up to date, and settings that shouldn't need a deploy to change.

What I did. The backend under that work. A review queue with temporary leases, so several reviewers can pull from it at once without stepping on each other: each one claims a batch, and whatever isn't finished in time goes back to the queue instead of getting lost. Role-based access with an identity plane separate from end users, a catalogue and settings the admin edits from the panel, and an audit trail with before and after values.

Waiting review queue claims a batch temporary lease Reviewer A Reviewer B finishes in time Done the lease runs out → back to the queue, nothing lost Audit trail who · what · before / after Access by role staff identity, separate Redrawn and simplified. It does not represent the real topology of anyone's system.

Annex C · reviewers pull in parallel, and nothing falls off the list.

Documents never leave through the front door

The panel doesn't reach storage directly. It asks the backend, the backend checks who's asking and serves the file itself. The store is never exposed to the browser — one less door, and every download passes through the same check as everything else.

Review queueTemporary leasesAccess by roleSeparate staff identityEditable catalogueOperational settingsChange auditingDocument proxy

Java · Spring Boot — PostgreSQL — queues · asynchronous work — roles · auditing

Experience file · piece 05 of 06 Inventory
05What I used, and what for

Backend

  • Java · Spring Boot
  • REST APIs · OpenAPI
  • Validation · DTO mapping

Data

  • PostgreSQL · PostGIS
  • A database per module
  • Modelling · versioned migrations
  • Geospatial queries

Cloud & infrastructure

  • AWS · Docker
  • Terraform
  • Config per environment
  • ECS Fargate · one IAM role each
  • Secrets Manager · STS temporary credentials

Integrations

  • External APIs · signed webhooks
  • Object storage
  • Providers behind an interface
  • Federated identity · staff tokens
  • Payments behind swappable adapters

Testing

  • Unit · controller slices
  • Integration with real containers
  • Full flow, end to end

Operations

  • Message queues · asynchronous work
  • Roles · auditing
  • Decisions written down
Experience file · piece 06 of 06 Next step
06The kind of work I'm ready for

This job taught me to build the backend of something real: APIs another team consumes, rules that hold on the server, integrations that fail without taking the rest down, deploys, and the internal tools that keep the operation running.

APIs and contractsREST APIs and OpenAPI contracts a frontend can consume without asking.
Modules with rulesBusiness logic validated on the server, with states modelled properly.
IntegrationsExternal services behind an interface, so swapping one isn't a rewrite.
Data and filesRelational databases, versioned migrations, and object storage.
DeploymentDocker, infrastructure as code, and configuration that lives in the environment.
Writing it downTechnical decisions documented, and work shared with frontend and product.