
Cultural Trails
A full web application that turns the canton of Vaud's cultural heritage into gamified, accessible walking trails: themed paths, points of interest with audio guides and quizzes, and an editor mode that lets local actors publish their own trails. I was the back-end lead.
- Role
- Back-end lead
- Year
- 2024
- Host
- HEIG-VD · Articulation Project
- Scope
- Team of five
- Shipped
- Live web app, presentation, report
The canton of Vaud's cultural heritage is rich but scattered, and hard to experience on foot in a guided, engaging way. The brief was to build a complete web application that turns it into gamified, accessible walking trails, and crucially, to let local actors publish and edit their own.
Underneath the product brief sat a real engineering problem: a content-heavy, map-based application with two very different kinds of user (people exploring trails and people authoring them), carrying multimedia, quizzes, and a layer of gamification, designed and built full-stack inside a student timeframe. I owned the back-end half of that.
- The back-end: the data model, the controllers and application logic, authentication and role-based access
- The route-planning integration, plus database seeding, migrations, and deployment
- Front-end components that talk to the database: the trail and POI creation forms, filters, and profile pages
- The early UX phase with the team
- The front-end lead's work, the UX design lead, and the visual/communication side
Team of five (Group Loomi) for the Articulation Project at HEIG-VD: Jérémy Martin (back-end lead), Antony Neyret (front-end lead), François Cuennet (UX design), Leïla Fidalgo (project manager), and Ariadne Melissargos (communications). Supervised by Laurent Berthelot (project management and technical), Jonathan Favre-Lamarine (UX/UI and design), and Noemi Romano (cartography).
One app, not a front and a back
We started from a Laravel Breeze base, which gave us authentication, Tailwind, and Vue out of the box, and then made the decision that shaped everything: Blade, Livewire, or Inertia. We chose Inertia. It let us build a single-page application with fluid transitions while writing the back-end as a normal Laravel app, with no separate REST API to design, version, and keep in sync.
That choice is why a five-person team could move fast. Inertia bridges the back and the front, so a controller returns data straight to a Vue page, and the boundary I owned (the models, the queries, the access rules) stayed clean and server-side while the front-end stayed reactive.


A content system for trails
The heart of the back-end is the schema. A trail (path) links to many points of interest and a point of interest can belong to many trails, so the join between them carries the order of the walk. Each point of interest holds its own audio guides, photos, and facts; each trail belongs to a theme. On top of the content sits a quiz model (quizzes, questions, answers) for the gamified stops.
Then there is the engagement layer, which is what makes it feel like a product rather than a catalog: favorites and completion histories for both trails and points of interest, achievements with a user pivot, reviews, and a role system underneath it all. Getting those relationships right up front is the architecture; everything else is built on them.




Explorers and editors, one schema
The app serves two audiences from the same code. An explorer browses the map, walks a trail, marks points of interest as done, and earns achievements. An editor (a local cultural actor) creates and edits trails and points of interest through guided forms, with their own creation and deletion flows.
That split is enforced by role-based access. Routes for favorites, the dashboard, achievements, and authoring are guarded by role middleware, so the same application safely exposes a public experience and a contributor's toolset without leaking one into the other.


Planning real walking routes
The interactive maps run on MapLibre, and the trails themselves are real routes, which means route planning between points of interest. We used OpenRouteService for that through its public API, calling it from the authoring flow to plan a route as a trail was being built. Self-hosting the engine was the obvious next step we flagged for a real deployment, to escape the public rate limits and keep that planning unconstrained.


A live, deployed full-stack web app at sentiers-culturels-vaud.ch, built on Laravel, Inertia, and Vue with a MySQL database.
A rich relational data model and a role-based content system that lets local actors publish their own trails, not just a fixed catalog the team controls.
Interactive mapping and route planning between points of interest, built on MapLibre and OpenRouteService, with self-hosting the routing engine flagged as the next step for a live deployment.
This is the project that taught me the back-end is mostly data modeling. The weeks I spent getting the relationships right (trails to points of interest, the engagement layer, the role system) are what let the rest of the build go quickly, and the messy parts later were almost always places where the model had been too loose. Choosing Inertia over a separate API was the pragmatic call I would make again: it traded a little setup for a lot less friction down the line.







