Alex HerreraSoftware developer · Cybersecurity focus
ES
← Back to projects

Professional

Star Cargo Service platform | Requests and case files

Eight online requests that end up in a portal where clients follow their submissions and the team handles them.

  • Full stack

1 / 27

Home page of the previous site, with a full-screen photograph of a lorry

Home, before. Four entries in the menu, with the service requests hidden in a dropdown.

Role
Development
Period
2026-05 – present

Stack

  • Next.js
  • React
  • TypeScript
  • Tailwind CSS
  • Auth.js
  • MySQL
  • Google Cloud Run
  • Playwright

Context

Star Cargo Service moves sea, air and land freight between six countries in Central America. Its site is the first commercial point of contact. An importer arrives there to request a quote, to check the consolidation corridors or to find the office that covers them.

The brief was a rebrand and a new platform, not a touch-up of the old site. The company sells into markets that do not share a language. It also needed whatever the site collects to end up in a case file the client can follow, not in an inbox.

Problem

On the old site, the service requests sat in a dropdown with no page of their own and did not appear in the footer. Three of them had no other link at all. An importer arriving from a search engine could not find how to request a quote.

Its portal returned 404 in production. A submitted request could not be looked up afterwards, by the client or by the team, so follow-up fell back to email and the phone.

Language was the other limit. A large share of shipments comes from markets that do not speak Spanish, and the site only served one of them well.

Technical decisions

The old site worked, so the immediate option was to edit on top of it and inherit its build, its dependencies and its earlier decisions. The result would have been the same site under another layer of styling.

A separate project was opened from day one, with its own build and dependencies and no shared configuration. A date was set after which the new project stopped taking code from the old site.

The backend started as a copy and is now this project’s code, edited here and nowhere else. Without that date there would be two half-merged projects and no single source of reference.

Permissions are not stored in this project. They are resolved against the ERP on every request, because copying them here would have meant keeping a second copy in sync with the ERP.

Architecture

The public site serves all four languages with the same structure and the same content. Each section declares a visual tone, and components read the variables in force where they are drawn. The same button therefore works in a light section and a dark one, with no conditionals.

The site’s eight service requests are sent to the ERP and land in a portal behind a session. The portal has fourteen screens for two audiences. Six are for the client, who follows their requests and opens their attachments. The other eight are for the team, who receive the requests sorted by type alongside clients, incidents and job applications.

The menu is not written by hand. Every entry is filtered by audience and by permission, so an option without permission is never drawn. An account with no permissions signs in and sees nothing.

Attachments open inside access control: the token is checked against the case file, the requester against ownership and the document against its folder. Clients open their own without leaving for external storage.

Result

The site is in production in Spanish, English, Chinese and Hindi. Clients follow their requests in the portal, without calling or writing to ask where they stand.

Employees sign in with Google, and the check is made on the token’s signed domain, not on the text of the address. Clients enter by invitation from an employee.

The set of checks is defined once and runs at two points: when a change is merged and when it is deployed. It checks:

  • the types and the tests;
  • a warning ceiling that cannot rise without a justification in the commit;
  • that all four languages have exactly the same translation keys;
  • that the content security policy is still active.

Deployment ends with a smoke test against the published site.

What I learned

Inheriting code from the old site meant applying every improvement twice. On top of that, any difference between the two looked like a sync error rather than a decision.

The cut-off date removed that ambiguity, because from that day the old site is a reference and not a source of changes. In a migration it is worth setting that date early, before there are two versions of the same fix to reconcile.