khalil.kouroghli
TUN FRContact

[01] 2024

TPP, Tourcom Payment Platform

Virtual cards and spend control for a network of travel agencies

01Agency userNuxt, own role area02TPP APIExpress, Keycloak RS25603Adyencards, balances, KYC04Webhooks7 event types, logged05AccountingCSV import, Excel01Agency userNuxt, own role area02TPP APIExpress, Keycloak RS25603Adyencards, balances, KYC04Webhooks7 event types, logged05AccountingCSV import, Excel
Select a box to jump to the decision behind it.

The problem

Tourcom's member agencies pay airlines and suppliers on behalf of travellers, and Tourfinance, the network's central hub, guarantees clients and suppliers if an agency becomes insolvent. The network needed one place to onboard agencies, fund them, issue them cards with rules attached, and reconcile every transaction, from head office down to each sales point.

My role

Full-stack developer at Everbloo since 2024, in a team of about twenty contributors. Since November 2024 I have pushed around 640 commits to the Nuxt frontend and 220 to the Express API, working with Adyen and Visa on the platform's card programme.

Decisions

D.01

One hierarchy, six role areas

Tourcom, sub-networks, agencies, sales points and corporates each get their own area of the app. The Keycloak token carries the entity type, and a global route guard sends every user to their area on login: 104 pages, one codebase, no user ever lands on a screen that is not theirs.

D.02

Virtual cards with rules attached

Cards are issued as virtual payment instruments on Adyen's Balance Platform. Transaction rules and reusable rule templates limit where a card can pay by merchant category, the full card number is revealed only through an encrypted public-key flow and every reveal is logged, and a daily job suspends cards that have expired.

D.03

KYC through Adyen-hosted onboarding

Agencies complete KYC on onboarding links generated through Adyen's Legal Entity Management API, so identity documents never pass through TPP. The platform tracks each agency's KYC timeline, surfaces the errors Adyen returns and can relaunch the request.

D.04

Adyen events drive the state

Seven webhook endpoints keep TPP in step with Adyen: account holders, cards, transfers, balances, credit limits and statements. When Adyen publishes an accounting report, TPP downloads the CSV, imports it and turns it into fees and interchange per agency, exportable to Excel.

D.05

Permissions as a bitmask

Seventeen permission flags combine per role and per entity, from a Tourcom super admin to an agency accountant or agent. Partners integrate through a separate public API with OAuth2 client credentials, API keys and a one-time code challenge.

D.06

Generators keep every module the same shape

A CLI built on ts-morph and Babel scaffolds each module the same way: model, migration, controller, service, Joi schema, types and Swagger docs. With twenty people in the codebase, the structure stays the same everywhere.

What it does today

  • Agencies are onboarded, funded, issued virtual cards and reconciled in one platform, from Tourcom's head office down to each sales point.
  • The API holds about 38,000 lines of TypeScript, 34 models and 104 migrations; the Nuxt app has 104 pages and 83 components.
  • Both sides work in English and French, with i18next on the API and vue-i18n in the app.
esc