Genoa Tours

Genoa Tours — tourist submission & approval platform

Travel agencies in Algeria and Morocco file tourist manifests for entry into Egypt. Before this, that ran on email and spreadsheets.

Proposed, built, delivered and self-hosted the whole system

The problem

Genoa Tours sits between North-African travel agencies and Egyptian entry approvals. An agency sends a manifest — flight details plus passport data for every tourist on it — and Genoa's staff review it, send it back for corrections, approve it, and issue a formal Arabic guarantee letter that the tourists travel on.

The whole loop was running over email. No status any agency could check without asking, no structured record of what had been submitted, and every guarantee letter assembled by hand. With 115 partner companies on the books, that does not scale, and the failure mode is a tourist at an airport with a wrong document.

What I built

Three pieces, all mine end to end — I proposed the system, built it, delivered it, and host it myself.

The partner portal is what the agencies see. They submit manifests, then track each one through review → revision → approval, and download the generated Arabic guarantee letter when it clears. The point was to remove the phone call: an agency should always be able to answer 'where is my submission' by looking.

The admin console is the internal staff surface. Review and approve submissions, manage the partner companies, set per-tourist pricing and track each partner's running balance and payments, edit the document template, and generate approval letters — single, or combined across multiple flights.

Both run on one shared ASP.NET Core 10 API over PostgreSQL with EF Core. Access is JWT with silent refresh and four roles, so a partner can never see another partner's manifests and staff permissions split between admin and general staff.

The parts that were actually hard

Bilingual, properly. Both front-ends are EN↔AR with full RTL — not a translation dictionary bolted on, but a layout that mirrors. Arabic is the language the guarantee letters are issued in, so this was load-bearing rather than a nicety.

Server-side Arabic PDF generation. The guarantee letter is a formal document with a fixed shape, generated on the server from the approved manifest. Getting Arabic to shape and render correctly in a headless Linux container — right fonts present, right text direction, no tofu — took longer than the feature it supports.

Combined multi-flight letters. A single approval often spans several flights, and the letter has to fold them into one coherent document rather than emitting one per flight.

Running it

I host the platform myself on a Linux VPS — Caddy terminating TLS in front, systemd supervising the services, PostgreSQL on the same box, and a self-contained .NET publish so the server needs no runtime installed. Schema changes go out as idempotent EF migration scripts.

Uploaded images and generated PDFs live on a persistent path outside the deploy directory, so a redeploy never takes client documents with it. That's the kind of detail nobody thanks you for until the one time it matters.

Stack

  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind v4
  • ASP.NET Core 10
  • PostgreSQL
  • EF Core
  • JWT auth
  • Caddy
  • systemd

Both surfaces are authenticated — partners are provisioned by Genoa, not self-signup — so there's no public URL. Live walkthrough or a sanitized screen-share on request.

Read the full CV · hello@theahmedali.com