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.

AnalyticsPipeline.html

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.

ComponentsDiagram.html

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.