Product & Software Engineering
Spotter
Spotter tells Técnico students which rooms are free, where they are, and for how long. I founded it in July 2026, put together a five-person student team, and run it as Product Owner across UX, frontend, backend and the university data integration.
At a glance
5
people on the team
18
students interviewed
1 week
Sprint 0: discovery
4 weeks
Sprint 1: the build
Sprint 2
in progress
The problem
When your usual spot is full, finding another one is guesswork. You walk to a building, look through a door, and try again. Nobody tells you which rooms are free, how long they stay free, or whether it is worth the walk. The information exists in the university's official timetables. It is just not pointed at the student standing in the corridor.
Sprint 0: deciding what not to build
We spent the first week on discovery rather than code. I interviewed 18 students, wrote the user stories with observable acceptance criteria, and split the summer MVP in two: first a room finder running purely on official timetable data, then student-submitted reports on top of it. That order mattered. A social layer built over a shaky data layer inherits every one of its problems, and we would not have been able to tell which was broken.
Sprint 1: the Core Room Finder
Four weeks, 9 July to 14 August. The team shipped a mobile-first app where you pick a campus, see the known rooms, read their availability state, filter and search, and open a room for detail. Behind it sits a REST API over models for buildings, rooms and events, an availability engine that computes state from official events rather than storing it, and an ingestion pipeline that pulls from the Fénix v1 API and normalises what comes back.
What I owned
- Discovery, MVP scope, user stories and observable acceptance criteria.
- The backlog and sprint tracker in Notion, with owners, points and dates on every task.
- Defining the five roles: Product Owner, Backend, Fénix Integration, Frontend UX/PWA, and Frontend Features and Analytics.
- Cutting Should Haves mid-sprint to protect the main flow.
- Reviewing deliverables across areas and holding the contracts between them.
- Writing the Sprint 0 and Sprint 1 documentation the team works from.
The hard part: saying what we do not know
An official timetable tells you when a room is booked. It does not tell you the room is free, only that nothing is scheduled. Those are different claims, and collapsing them into a green 'Available' badge is how a product loses a user's trust on their first walk to an empty-looking room that is full. So we had to design a third state, Uncertain, and decide how much of that ambiguity to put in front of someone who just wants somewhere to sit.
- Availability is computed, not stored: it depends on events, time, intervals and opening hours.
- 'Free soon' is capped at 15 minutes, because a longer promise is one we cannot keep.
- Empty results, a failed request and uncertain data are three different screens, not one.
- Student reports will never be used to paper over an ingestion or algorithm error. If a room is wrong, we fix the source.
Where it stands
Sprint 1 closed with an operational baseline ready for an internal pre-demo: the areas integrated, real data flowed end to end, and the main flow worked on a phone. It has not yet been validated by students in a normal week, because we built it over the summer, when nobody is looking for a room during exam season. Sprint 2 is fixing the trust and mobile regressions first, then adding occupancy reports, canteen information and the beta. Reports, login, reservations and analytics were all deliberately out of Sprint 1.
Stack and how it was chosen
I am the Product Owner, not a developer on this project. I scoped the stack decision as a research task, asked the engineering side for a comparison with reasons, reviewed what came back and approved it for the MVP. The list below is their work; the process around it was mine.
Frontend
- React, Vite and Tailwind CSS.
- Mobile-first, since the whole point is using it while walking across campus.
- Filter state in query parameters, so a search can be shared as a link.
- Routing, pagination and infinite scroll, with alternative states for empty, error and uncertain.
Backend and data
- Django and Django REST Framework.
- PostgreSQL, with SQL annotations so availability can be sorted, filtered and paginated in the query itself.
- A Python ingestion pipeline over the Fénix v1 API: collect, filter, normalise, load.
- Tests covering the availability logic, intervals, endpoints, filters and import.
What I learned
- A technical demo and a validated product are not the same claim, and it is tempting to report the first as the second.
- Official data is raw material, not a finished product. The gap between 'no event scheduled' and 'genuinely free' turned out to be a product decision, not a data one.
- Cutting scope mid-sprint is a product decision. It reads as lowered ambition to a junior team, so it has to be explained as protection of the main flow.
- Handoffs need explicit contracts. An undefined state in the backlog becomes ambiguous UI, then an unclear API field, then a bad error message.
- Mocks hide everything that matters: latency, network errors, incomplete data and mobile edge cases only appear against a real API.
Documentation
These are the team's internal sprint records, in Portuguese, exactly as we use them. They are working documents rather than a polished case study, which is the point: they show the decisions, the cut scope and the debt as they were actually written down.
Sprint 0
Discovery, the 18 student interviews, MVP scope, stack and data-source research, and the initial backlog.
In review
Sprint 1
Core Room Finder delivery, evidence per user story, the Fénix integration, QA and the debt carried into Sprint 2. Written and under team review before publication.
In progress
Sprint 2
Data-confidence fixes, occupancy reports, canteen information and beta feedback. Will be published when the sprint closes.