Sprint 2 - ISIS3510-202620-Team41/ISIS3510-202620-Team41-WIKI GitHub Wiki
Sprint 2 - Weeks 20/09/2026 - 03/10/2026
BQ Questions
| BQ | Type | Analytics Engine Owner | Rationales |
|---|---|---|---|
| Is the average loading time of the app less than 1 second? | Type 1 | Tomas | Implemented to provide instant access during brief class breaks, ensuring students can check friend availability and recommendations without friction. |
| Which screen or app component has the highest crash rate? | Type 1 | Juan Sebastian | Implemented to maintain high app stability by identifying and fixing broken components before they impact core user features. |
| What is the proportion of recommended activities that are selected by students during their available free time windows? | Type 2 | Martin | Implemented to validate that suggested places and activities resonate with users during their free gaps, ensuring high click-through and adoption rates. |
| Which of the recommended categories is most frequently selected during the different free time durations? | Type 2 | Sebastian | Implemented to uncover preference patterns across different time slots, enabling the app to tailor categories based on whether students have quick breaks or longer gaps. |
| What percentage of active users use the Friend Availability feature to create or join a plan? | Type 3 | Alejandra | Implemented to evaluate feature adoption and utility, determining if social availability tools effectively motivate users to create and join group plans. |
Implemented Features
| Issue | Feature | Kotlin owner | Flutter owner | Backend owner |
|---|---|---|---|---|
| #11 | Add Profile Picture Camera | Sebastian | Alejandra | Tomas |
| #12 | Track Recommended Activities Selected During Free Time | Martin | Juan Sebastian | Tomas |
| #13 | Recommend Activities by Nearby Meeting Point | Martin | Alejandra | Tomas |
| #14 | Recommend Activities Based on User Preferences | Martin | Alejandra | Tomas |
| #15 | Add Login Authentication | Sebastian | Juan Sebastian | Tomas |
| #16 | Sync with External Calendars | Martin | Juan Sebastian | Tomas |
Analytics Pipeline
We built the analytics engine as a separated services in order to measures the app without slowing down the app or breaking it. The different event comes from small events, where then they are stored and proccessed in order to answer the five business questions selected.
The information is split if the backend arleady knows the information such as recommendations and joins and the rest is sent by the phones such as loading time, screens and crashes. Then after some verifications its stored in a SQLite database (in this case it was chosen because it need no setup and its size its enough for our case. It is important to note that every evento has a unique id, so a retry never counts twice, and also every evento carries a user id so we can count real users instead of raw clicks/taps. Each metric lives in its own small file, so we can add or change one. Finally the results are read by the dashboard and showed in the different charts for the team to see in one place.
Architectural
The diagram shows the parts of the system and how they communicate with each other. To build it, we first identified the three parts that run separately in the application, the Android application, the backend and the analytics engine, each represented in a container of a different color. Within each one, its components were drawn. In the application they were organized by layers, following the MVVM pattern, the UI, ViewModel, repository and network. In the backend they were organized by functionality like the authentication, users, activities, schedules, storage and analytics. Separately, we added the external services the system depends on but that the team does not develop, such as Google Identity, Google Calendar, the database and the image storage.
Architectural design
The previous section showed what the system is made of. This section explains how those parts work together over time.
To do this, we use sequence diagrams. While a component diagram is a static map that simply shows the parts, a sequence diagram is a timeline, read from top to bottom, it shows exactly who sends what message to whom, in what order, and what reply comes back. It is the ideal tool for answering questions about order, interaction, and handling errors.
We chose to show three main flows instead of a diagram for every single feature:
Diagram A — Signing in and staying signed in (Feature #15): Included because authentication is the foundation for everything else in the system. It also shows what happens when a token expires during normal use.
Diagram B — From the user's calendar to a suggested activity (Features #16, #13, #14, and #12): Groups these four features because they form a single chain: without the calendar, there are no free gaps, and without free gaps, there is nothing to suggest.
Diagram C — Taking a profile picture (Feature #11): Chosen because it is the only process where a single action saves data to two different places at once, making the exact order of steps crucial.
To keep the diagrams easy to read, we grouped several internal components into a single participant (for example, drawing the entire backend as one line). The detailed structure was already documented in the previous map.
Each diagram includes a brief explanation of the design decisions made and the reasoning behind them.
When a user signs in, the server hands out two keys: a short one that travels with every request and expires in 15 minutes, and a long one that lasts 30 days and is only used to ask for a new short key. Two keys were chosen instead of one because a single long-lived key would be dangerous if stolen, while a single short-lived one would force the user to sign in again every 15 minutes. The diagram also shows the decision that matters most in day-to-day use: when the short key expires, the network client gets a new one and repeats the request by itself, so the user is never thrown back to the login screen in the middle of something. Each time the long key is used it is replaced and the previous one is cancelled, so a stolen key stops working as soon as the real user comes back.
sequence-diagrams-A-Signing in.html
This flow groups four features because they form a single chain and would be misleading apart. The main decision shown is that the keys granting access to someone's Google calendar are scrambled before being stored: if the database ever leaked, plain keys would expose every user's schedule. The second decision is that statistics never make the user wait. When an activity is chosen, the backend leaves a note in a queue and answers immediately, and the note travels later on its own; the queue has a limit, so if the statistics service is down the notes are discarded instead of slowing the app. Losing a statistic is acceptable, making someone wait is not. The app also reports directly to the statistics service, so its figures keep arriving even if the backend is down.
sequence-diagrams-B - Suggesting activities.html
A single action writes to two different places, the image storage and the database, which is why the order of the steps is the point of this diagram. Photos taken with a phone carry invisible extra data, including the exact spot where they were taken, so the server rebuilds the image instead of saving the file as it arrives; publishing it untouched would mean publishing where the user lives. The picture is shrunk twice, once on the phone to avoid spending mobile data and once on the server, because a modified app cannot be trusted to have done it. Finally, the old file is deleted only after the new one is safely stored: in the opposite order, a failure halfway through would leave the user with no picture at all.
sequence-diagrams-C - Profile picture.html
Architectural styles
| Style | Implementation rationale | Responsible |
|---|---|---|
| Layered architecture | Each layer has one job, so the code is easier to read, change and test. | Tomas |
| Stateless REST | The server keeps no session. Each request proves who it is by itself, which fits a mobile app and is easy to scale. | Sebastian |
| Modular monolith | There is one app to deploy, but each feature lives in its own package, so a change stays in one place. | Tomas |
| MVVM | Compose screens handle presentation, ViewModels coordinate UI logic/state, and repositories handle data access. | Martin, Tomas, Juan Sebastian, Alejandra, Sebastian |
| Client-Server | The Kotlin app acts as the client and communicates with the backend through REST endpoints. | Martin, Tomas, Juan Sebastian, Alejandra, Sebastian |
Architectural tactics
| Tactic | Implementation rationale | Responsible |
|---|---|---|
| Authenticate actors | We check who is calling on every request. | Sebastian, Juan Sebastian |
| Authorize actors | The user comes from the token, never from an id sent by the client, so nobody can act as someone else. | Sebastian |
| Encrypt data | If the database leaks, passwords and tokens are still useless to an attacker. | Sebastian, Tomas |
| Limit access | Repeated failed logins get blocked, which stops brute-force attacks. | Sebastian |
| Validate input | Bad data is rejected early: wrong fields, fake images, huge search ranges. | Tomas, Juan Sebastián, Alejandra |
| Graceful degradation | A broken optional part must not break the rest. Without Google credentials or with the engine down, the API still works. | Tomas, Juan Sebastian, Martin, Alejandra |
| Increase resource efficiency | The cheap filter runs in SQL first, and the expensive distance math runs only on the few results left. | Tomas |
| Use an intermediary | A change in Google, the database or the JSON format affects only one place. | Tomas, Martin |
| Abstract data sources | Tests run without network or credentials because external parts are replaced with mocks. | Tomas |
| Persistent session state | Allows a rapid way for the application to restore an existing authentication session after restart. | Juan Sebastián |
Design patterns
| Pattern | Implementation rationale | Responsible |
|---|---|---|
| Service Layer | One place coordinates the business steps, so controllers stay small and simple. | Tomas, Juan Sebastian, Alejandra |
| Repository | The database is hidden behind an interface, so we can change it without touching business code. | Tomas, Martin |
| DTO | The API never returns database entities, so secrets like the password hash cannot leak by mistake. | Tomas, Sebastian |
| Dependency Injection | Classes get what they need through the constructor, so tests can swap real parts for fake ones. | Tomas, Juan Sebastian, Alejandra |
| Chain of Responsibility | Every request goes through filters before the controller. If the token is bad, the chain stops with a 401. | Sebastian |
| Strategy | The password hashing algorithm can be changed without touching the login code. | Sebastian |
| Adapter | Outside services sit behind our own interface, so the rest of the code does not depend on Google or on the disk. | Juan Sebastian, Tomas, Martin |
| Producer–Consumer | Metrics are sent from a background thread, so users never wait for the analytics engine. | Tomas |
| Observer | Compose state changes cause the UI to react automatically, such as recommendations loading or Unirme → Unido ✓. | Martin, Juan Sebastian, Alejandra, Sebastian |
| Singleton | A shared ApiClient instance centralizes Retrofit/network configuration. | Martin, Juan Sebastian |
| Facade | For a simpler use in hiding the authentication, tokens, http headers and json processing for the application in updating information | Juan Sebastian, Alejandra |
Ethics Video
As GitHub has a strict policy when uploading files larger than 10mb to a wiki page, we decided to upload the video to YouTube to allow the examinators to review the video easily. However, we will also provide a download link to prove this video wasn't modified after the deadline of the Sprint 2 deliverable.