Skip to content
theakrista.dev
Case Studies

2026 - Present

Private client work

Online Travel Agency Platform

Designing the backend for a new OTA product, partner API integrations behind clean adapter seams, and growing the team that ships it.

Senior Full-Stack DevOps Engineer · backend architecture lead

Node.jsExpressTypeScriptMongoDBPostgreSQLREST APIsOpenAPIRender
pattern isolating every partner API behind one contract
Adapter
query-optimization guidelines became the team standard
Adopted
onboarded and mentored a new engineer
1 → team
architecture designed for the next partner, not just the first
Greenfield

The Problem

The company's next product was an online travel agency, bookings built on top of external partners' inventory. Every partner API disagrees with the last one: different authentication, pagination, data shapes, rate limits, and error semantics. And the roadmap adds partners, not just features.

The naive approach (wiring each partner directly into the business logic) works for the first integration and collapses by the third, when the core codebase has become a museum of special cases that nobody can change safely.

This was also the first project where I wasn't building alone: a new engineer was joining the team. The architecture had to be teachable, conventions written down as guidelines and patterns, not conventions living in my head.

The Constraints

Partners don't share a schema

Rates, availability, booking states, and errors arrive in a different shape from every partner. The core domain needed one internal model, with all translation pushed to the boundary.

The Nth partner must be boring

Success for this architecture isn't the first integration working, it's the fifth integration being routine. Adding a partner had to mean writing one adapter, never touching the booking core.

A brand-new team

Onboarding an engineer while designing the system meant every decision had to be explainable and documented. Patterns that need their author present to apply correctly don't scale past one person.

Search is read-heavy and unforgiving

Travel search hammers the data layer, and a slow query is an abandoned booking. Query discipline had to be a written standard the whole team applies, not an optimization pass someone remembers later.

The Architecture

A core booking domain that never talks to a partner directly: every external API sits behind an adapter that translates it into one internal contract, so search, booking, and operations code is written once, and the next partner is one more adapter, not one more rewrite.

  • Each partner adapter owns everything partner-specific (auth, pagination, retries, quirks) and exposes the same interface as every other adapter. Adding a partner means writing one adapter, not touching the core.
  • Normalization happens at the boundary: rates, availability, and error semantics are converted into the internal domain model immediately, so no partner-specific shape ever leaks inward.
  • The query-optimization guidelines came out of real slow paths, then became the written standard for every new endpoint, review comments turned into a checklist anyone can apply before opening a PR.
  • Releases flow through the same staging-to-production process I established for the rest of the company, so the new product inherited operational discipline from day one.

The Trade-offs

Every architecture is a set of bets. These are the ones I made, and what I gave up to make them.

Partner integrations

An adapter layer with one internal contractoverDirect integration per partner in business logic

The abstraction costs extra work on partner one and pays it back on partner two. The core stays partner-agnostic and testable against fake adapters, and no partner's quirks can ever hold the domain model hostage.

Knowledge transfer

Written guidelines and reusable patternsoverCorrecting things in code review

Mentoring through review comments fixes one PR; guidelines fix every future PR. Writing the query and adapter standards down turned my judgment into something the team applies without me in the room.

Data layer

The databases the team already operates, tuned hardoverIntroducing a search-optimized store

A greenfield product doesn't need a greenfield ops burden. Indexing and query discipline covered the real load, and the team kept a stack it already knows how to run, back up, and debug.

Sequencing

Architecture and seams first, features secondoverThe fastest possible demo

Partner seams and the domain model are nearly impossible to retrofit once integrations multiply. Spending the early weeks on boundaries was the cheapest moment that decision will ever have.

The Outcome

The OTA backend is in active development on an architecture designed to scale with partners, and with the team.

  • Designed the backend architecture and partner integration layer: every partner API sits behind a reusable adapter with a single internal contract.
  • Authored query-optimization guidelines that the team adopted as its standard for new endpoints.
  • Onboarded and mentored a new engineer (the first step from sole engineer to engineering team) while remaining final reviewer for production releases.
  • Partner integrations ship behind clean seams, keeping the core booking domain free of partner-specific code as the product grows.

Lessons Learned

Abstractions are cheapest at the boundary

Inside your own code, premature abstraction is a tax. At the edge where external APIs live, it's insurance you always end up claiming, the second partner proves the adapter, and the fifth one thanks you for it.

Design for the second partner

The first integration always looks like the general case, and it never is. Designing as if the second partner were already signed is what keeps the first one's quirks out of the domain model.

Mentoring is an architecture concern

A system you must hand to a new engineer forces honesty: conventions written down, seams that explain themselves, patterns that survive their author leaving the room. Building for the team made the architecture better, not just more documented.