
Corporate Website
EuroTech's public face: a four-language marketing and application site. The language is read from the first segment of the URL and a single route tree produces output in four languages. Same organisation as the portal, but a separate application. Archived — active development ended at the close of 2025.
The organisation's public face had one job: to carry an applicant arriving in one of four languages to the point where they leave their details. The difficulty here is not translation but route design. In a multilingual site, adding a language later breaks addresses and loses the search visibility accumulated up to that point. The second issue is source tracking: where a visitor arriving from an advert came from should not disappear when the form is submitted — otherwise which channel works is simply unknown. The third is analytics and cookies: the analytics code had to stay unloaded until consent was given.
Three visitors. The applicant: arrives in one of four languages, browses programme and content pages, and eventually fills in the application form. The parent or institution: reads the same content looking for reassurance. The organisation's own team: sees the incoming application and the campaign source — that part runs on the portal side.
As developer, the whole site: route and language structure, pages, application and campaign flow, cookie and analytics layer.
A server-rendered site on Laravel 10. The language is defined as the first segment of the route group and read by a middleware: the middleware compares the incoming value against the four supported languages, falls back to the default if it is invalid, and installs the language as a default parameter for all subsequent URL generation. That way a single route tree produces output in four languages and templates do not have to carry the language. The data side is narrow: two models — user and campaign. The application form writes a record to the database and sends an email notification; bot protection sits on a separate verification route. Cookie consent lives in its own controller, and whether the analytics code loads depends on that consent. Old language paths are preserved through permanent redirects.
The language is the first segment of the route group and is validated by middleware, falling back to the default if invalid. Because the language is also installed as a default parameter for URL generation, templates do not have to carry it — a link written anywhere comes out in the right language. That is what lets four languages live in one route tree.
Trade-offThe path segments are shared across all four languages; only the prefix changes, the segments themselves are not translated. For search visibility that is a weaker choice than localised paths. In VAP Turizm I solved the same problem the other way round: there the paths themselves change with the language, at the cost of three definitions for every new page.
Where a visitor arriving from an advert came from should not disappear when the form is submitted. Keeping the source in a separate model rather than mixing it into page content means the source record survives content changes.
Trade-offThe source is only captured on first contact; if a visitor returns through another channel the first record stands and last-touch information is not kept. So the record answers "where did they hear about us", not "which channel converted".
Consent state is managed in a separate controller, and whether the analytics code enters the page depends on it. Analytics do not load before consent; this is a compliance decision made at the cost of measurement accuracy.
Trade-offVisitors who do not consent never appear in the analytics, so reported traffic stays below real traffic. That difference was accepted.
The language structure changed over time and links to old addresses kept arriving. Rather than being deleted, old paths were put behind permanent redirects, so external links and search-result entries did not break.
Trade-offThe redirect table grows over time and nothing is ever removed; each redirect is a small maintenance burden and a rule evaluated on every request. There is no measurement showing which redirect still receives traffic.
The site was written on the same framework as the portal, and that was deliberate: when two applications of the same organisation share a language, a deployment style and an operating model, maintenance runs on one mental model. Server-rendered templates were enough for a site consisting of marketing content and a form — carrying a separate frontend application and an API contract would not have paid for itself. The site and the portal were nevertheless kept as separate applications: having a public surface share a deployment with a closed portal would have widened the attack surface for no reason.
The only public write path is the application form, protected by a verification endpoint on its own route. Outside that form there is no endpoint through which a visitor can write to the database. Cookie consent is managed in a separate controller and third-party analytics code does not enter the page before consent. Because the site and the portal are separate applications, compromising the public surface does not mean access to portal data — that separation is the most valuable part of this design.
There is no stored, date-stamped measurement output for this site, so no score is written here. Structurally, pages are produced on the server and sent as full pages; no application layer is carried on the client. Because analytics load only after consent, visitors who decline also carry no third-party script weight.
The clearest lesson I carried out of here is path localisation. On this site only the language prefix changes while the segments themselves are identical in all four languages; in VAP Turizm I solved the same problem the other way round and split the paths by language. The second lesson is redirects: not silently losing a published address is the one thing that cannot be repaired later. What I would do differently is the measurement side: the redirect table grew but nothing shows which rule still receives traffic, so no redirect can be safely deleted. I closed the same gap on the inventory side in Ops Panel — without seeing how long a record has been in a given state, you cannot decide which one to clean up.
Tell me what you want to build; I'll tell you up front how long it takes and where to start.