Full-Stack Developer
frontend, backend,servers and deploys.
I design, build, ship and maintain business-critical, high-concurrency web systems: interfaces, backend, frontend, servers and operations.
Full-Stack Developer
I design, build, ship and maintain business-critical, high-concurrency web systems: interfaces, backend, frontend, servers and operations.
Context boundaries, API contracts and trade-offs settled up front.
Strict typing, bounded transactions and idempotent writes.
SLOs with error budgets, declarative IaC and rehearsed rollback.
Software engineer with 10 years building and operating production web systems. I cover the full cycle: from the domain model to the server that keeps it running.
I work the whole system: interface, API, data and the infrastructure that runs them. I administer Linux servers, TLS, reverse proxies, deployment pipelines and ongoing management.
Software running in production, built for clients who own the source. That is why nearly every repository is private: instead of code, you get the architecture, the stack, the engineering decisions holding each system up, and screenshots of the product at work.
Modular modernisation of a legacy banking core
Private repository 2 Anonymous, verifiable electronic voting on a purpose-built blockchain
Public repository Agent council that decides whether code should be written at all
White-label editorial CMS built to replace WordPress
Private repository Sales and collections management on Laravel 12
Private repository Church administration migrated off Filament
Private repository Records, treasury and audit rebuilt on TanStack Start
Private repository Institutional portal running on the EchoPress platform
Private repository Piano chord study app with an interactive keyboard
The language is chosen for the problem, not out of habit. Here is what I build each layer with — from transactional processing to the interface — and what each tool actually solves best.
Server-side languages: business domain, data, processing and APIs.
9 technologiesThe workhorse for management systems: invoicing, inventory, collections and admin panels that run every single day.
For systems where a bug costs money: banking cores, transactional processing and services expected to run for years without a rewrite.
Where the job is moving and reshaping data: batch processing, reconciliation, automation and integrations between systems that do not talk.
When performance and memory safety are non-negotiable: the compiler rejects entire classes of bugs before they ever reach production.
Services that compile to a single binary and deploy with no dependencies: ideal for running on the client site, even with no network.
The one language that runs in the browser and on the server: a single data model and a single validation shared by both halves of the product.
What keeps you from rewriting authentication, permissions, migrations and queues on every project.
The framework that takes a management system from zero to production fastest: authentication, queues, permissions and admin panel already solved.
When the system lives off its data: the admin panel is generated from the model, so back-office management exists from day one.
The banking and enterprise standard on the JVM: transactions, security and legacy integration with guarantees an auditor will accept.
Platform fundamentals, language, tooling, state and quality.
13 technologiesThe platform ships native dialogs, popovers and disclosures. Using them removes kilobytes of brittle JavaScript and the accessibility bugs every UI library dragged along.
Nesting, :has() and container queries made preprocessors obsolete. A component adapts to its container instead of the viewport, and @layer ends the specificity wars for good.
Dynamic JavaScript accrues debt because nobody refactors blind with confidence. Strict typing turns the backend contract into something the compiler checks, rather than something you hope holds.
It kills bloated stylesheets full of dead code and the runtime cost of CSS-in-JS. Only the classes you use get compiled, so there are no global collisions and no CSS nobody dares delete.
Replaces Webpack and Babel pipelines that took minutes to boot and configs nobody wanted to touch. With the bundler rewritten in Rust, the edit-and-see cycle stops being a bottleneck.
Fixes the anti-pattern of stuffing network responses into a global store. Loading states, errors, deduplication and revalidation stop being hundreds of race-prone lines.
Ends the flaky suites that depended on arbitrary waits. Auto-waiting and hermetic browser contexts make end-to-end tests something you can actually trust to block a deploy.
They decide where rendering happens and how reactivity is orchestrated. The stack above holds them up.
The base everything I build on TanStack Start runs on. With Server Components the heavy logic moves back to the server and the browser only receives what genuinely needs to interact.
Server Components run data access on the server and ship zero JavaScript for every non-interactive component. No more megabytes just to paint a nearly static view.
Not every site needs to be an SPA. Islands architecture ships plain HTML and hydrates only what genuinely interacts, which is what keeps Core Web Vitals healthy.
Reactive UI without standing up a separate client app. State lives on the server, so there are no two data models to keep in sync and no intermediate API to maintain.
Stands up a full admin panel over Laravel in hours: resources, tables, forms and permissions already solved. The price is coupling your interface to the package release cycle, and that is a call to make deliberately.
A fully opinionated framework: dependency injection, routing, forms and HTTP all come decided. On large teams that stops every module from inventing its own architecture.
Engines, cache and data models: where state lives and under what guarantees.
6 technologiesThe engine already running in most of the legacy systems I inherit. Migrating away is rarely the answer: the answer is understanding the indexes and the queries someone left unoptimised.
My default when the data matters. Constraints, transactions and serious types let business rules live in the database instead of depending on every application remembering to enforce them.
It fits when the schema changes often and each document is read whole: catalogues, events, logs. It stops fitting the moment you need to join collections or guarantee consistency across them.
A complete database inside one file, with no server to administer. It is what lets a system run on the client site with no network and no dependency on someone else’s infrastructure, as in Electorium.
It absorbs the repeated work that never needed to reach the database: sessions, cache, queues and rate limits. Used well, half a system’s slow queries simply stop running.
PostgreSQL’s binary document type: it stores flexible structures and indexes them with GIN, without leaving SQL. It saves you from running a separate document store just because a few fields vary.
What I work with every day and why each one is there. There is no commercial arrangement with any of them: these are working decisions, not sponsorships.
Source of truth for the code and the history of every decision: branches, reviews and continuous integration actions.
The environment is declared once and runs the same on my machine, the client’s and the server. A deploy means pulling a tagged image, not rebuilding in production.
DNS, certificates and caching in front of the origin server. It absorbs traffic and attacks before they reach the machine actually holding the application up.
Where an API is exercised and documented before the frontend depends on it. Collections leave the contract written down and runnable, not buried in a chat.
PhpStorm, IntelliJ and GoLand understand the whole project, not just the open file: renaming a method across the codebase stops being search and replace.
Architecture decisions and incident notes are written to plain local files, linked to each other and dependent on nobody’s service.
Remote access to client infrastructure over WireGuard, from a provider that keeps no logs and requires no identity to operate.
Desktop and server on the same system family: what compiles on the development machine behaves the same in production, and the differences are decisions rather than accidents.
Where the system lives in production: long support and predictable change.
Where the systems I administer actually run: supported to 2029, predictable repositories, and the base Docker, Nginx and the certificates sit on.
The standard when a client demands contracted support and certifications: banking, health and public bodies that need someone accountable on the other end of the line.
The branch that feeds RHEL: it lets you test against what the enterprise server will receive next cycle, before it reaches the client.
Where it is written and tested: recent tooling and parity with the server.
The desktop counterpart to the server: the same library versions, so what compiles locally compiles the same way in production.
Recent kernel and toolchain, to try today what reaches RHEL two years from now. It is the Red Hat ecosystem test bench, not a long-term support system.
The machine I design, write and connect to infrastructure from. Unix underneath, so the same terminal tooling as on the server.
Every project ships where its load and its budget justify. These are the platforms I administer and the reasoning behind choosing between them.
Capacity that follows demand and is paid for by use.
EC2 when the system needs to grow or shrink with demand, and Lightsail when a project just needs one predictable machine at a fixed price.
The middle ground between price and control: clean instances in minutes, without the configuration surface of an enterprise provider.
The best resource-to-cost ratio on the market, with EU data centres. For sustained workloads the saving against the big clouds is an order of magnitude.
Fixed resources, full system control and predictable cost.
A machine with fixed resources and full system access: no neighbours sharing CPU and no limits imposed by the provider panel.
For sites that do not justify running a whole server: domain, mail and deployment solved without weekly maintenance.
Infrastructure and domains in Latin America, with local support and billing. Lower latency for regional users and paperwork that does not cross borders.
A fast site does not come from code alone: it comes from every image shipping in the right format, size and compression. I prepare the assets myself — SVG for vectors, WebP and AVIF for photography, WebM for video — instead of publishing whatever the designer sent.
Logos and icons exported as SVG: a few kilobytes, sharp on any display, and inheriting the theme colour instead of needing one light and one dark version.
Cropping, retouching and export to WebP or AVIF at the exact size it renders. A badly exported photo can outweigh every line of code on the page.
Many clients hand over their brand as legacy .cdr files from their print shop. Being able to open and convert them to web formats avoids rebuilding an identity from scratch.
From the first conversation to year-three maintenance. Every stage rests on the stack, the infrastructure and the systems shown above on this page: follow the link and check it.
It starts with a conversation, not a quote. Understanding the real problem, the constraints and what happens if it goes unsolved usually changes the solution before the first line is written.
I model the domain and settle boundaries and contracts before any code. Decisions are written down with their trade-offs, so they can be argued and reversed without archaeology.
Interface, API and data as one system typed end to end: bounded transactions, idempotent writes and queries that do not grow unchecked.
Business rules live in the database, not in the hope that every application honours them. Cache absorbs the repeated work so the engine only does what matters.
From container to domain: reproducible environments, TLS, reverse proxies and deploys that repeat identically and roll back without drama.
A delivered system is not a finished one. Administered servers, backups proven by restoring them, and evolutionary maintenance for as long as the product lives.
The people who open these systems every day to do their work. No scores and no stars: what they describe is what changed in their routine once the system went live.
We used to close the month going through notebooks and calling each collector one by one. Now I open the system and the balance is right there, with who paid and who did not. What I appreciate most is that when something does not add up, Pablo looks at it the same day.
I asked for something simple so the kids could study chords without depending on me. It turned out better than I pictured: they go in, pick a note and see the keyboard. Several of them now practise on their own at home, and that never used to happen.
The weekly close used to take me a whole afternoon between spreadsheets. Today I do it in a while and the daily ledger balances. When we asked for a change in the accounting codes, we did not have to explain twice what it was for.
We came from a system where every update broke something. Pablo rebuilt it and since then we have worked without worry. It is not just that it works: it is that you ask a question and someone answers who understands the problem.
The trial went perfectly. The terminals ran with no internet all day and at closing we had the results with their backup. Being able to show that every vote was recorded and that nobody knows who voted for what — that is what convinced people.
If you need to sort out an architecture, build a product or stabilise a platform already running in production, tell me the problem. You get an honest read back: whether I can solve it, what I would do first, and how long it takes.
For proposals, scope and anything worth putting in writing.
For a short conversation about something specific.
Track record, recommendations and professional contact.
Public repositories and open source.