Sprint 2 - Moviles-SEC-2-G25/Wiki GitHub Wiki

1. Business Questions

Type 1 — App Telemetry

BQ1:
At what specific software module does the app most frequently crash when a user brings the app back to the foreground after tracking a location-based quest in the background for more than 10 minutes?

BQ2: Group Challenge Module
How many participants successfully join a Group Challenge, and how often does the Group Challenge module fail to create, register, or update participant progress during an active challenge?

Type 2 — Direct User Experience Improvement

BQ3: Onboarding Drop-off
At which step of the initial preference setup do users most frequently abandon the process, and how does completing each step affect the acceptance rate of their first recommended Side-Quest?

BQ4: Instant Plans
How much does providing ready-to-execute Side-Quest plans reduce the time and number of interactions required for a user to start a Side-Quest?

BQ5: Personalized Quest Recommendation
Given the user's available time, preferred level of social interaction, interests, and previous quest interactions, which three available Sidequests have the highest relevance for the current session?

Owner: Sebastián Maldonado
Status: Implemented and validated

Rationale:
The purpose of BQ5 is to reduce the effort required to choose a Side-Quest by ranking the most relevant available activities for the current session. The recommendation considers user preferences and session information while preserving user control through Explore filters and the Not for me interaction.

Implementation:
BQ5 is implemented through the shared Supabase public.recommend_quests PostgreSQL RPC. The Kotlin client requests up to three recommendations and emits recommendation_shown analytics events. The Analytics Engine includes a BQ5-specific SQL query and pipeline job that reconstructs the latest recommendation batch and stores the resulting evidence in analytics.bq_results.

Validation:
BQ5 was validated end-to-end from the Kotlin application by changing available time, interests and location mode, and by verifying that Not for me removes a recommendation and requests a replacement when another candidate is available.

BQ6: Quest Abandonment Reasons
What are the most frequent reasons users select when abandoning an active Side-Quest, and how do these reasons vary according to the quest's estimated duration, cost and distance?

Type 3 — Feature Analysis

BQ7: Group Challenge Adoption
What percentage of active users join at least one Group Quest Challenge, and how does the completion rate of group challenges compare with individual Side-Quests for the same users?

BQ8: Recommendation Diversity
How does increasing the diversity of Side-Quest recommendations affect acceptance and return rates among users who have already completed multiple Side-Quests?

BQ9: Quest Category Performance What is the completion rate of each Sidequest category among quests accepted during the last 30 days, and which categories have the lowest completion rates?

BQ10: Location-Independent Mode Usage
What proportion of sessions uses the location-independent filter instead of location-based Side-Quests, and how do time of day and weather conditions affect that proportion?

Type 4 — Benefits from Data

BQ11:
What are the specific commercial blocks in Bogotá where users spend more than 20 minutes completing physical sidequests on weekends, providing high-value foot-traffic data to pitch to local businesses for sponsored "checkpoint" quests?

BQ12: Sponsored Quest Performance
What is the acceptance and completion rate of sponsored Side-Quests compared with non-sponsored ones, segmented by business category and by the user's declared interests?

Type 5 — Combined Business Questions

BQ13: Adaptive Quest Optimization:
For users who frequently skip recommended Side-Quests, how does automatically adapting quest duration, difficulty, and category based on previous interactions affect both recommendation acceptance rate and overall quest completion rate?

BQ14: Social Comfort Personalization:
For users with low willingness to participate in socially demanding activities, does adapting Side-Quest recommendations to their preferred social exposure level increase completion and return rates compared with showing non-personalized social challenges?

2. Analytics Pipeline

2.1 Analytics Pipeline Rationale

Both mobile applications use a shared analytics event contract and store interaction events in the shared public.analytics_events table.

The Analytics Engine reads operational data and analytics events from PostgreSQL, computes the implemented Business Questions, and writes analytical outputs to the analytics schema.

Separating event collection from analytical processing allows Kotlin and Flutter to share the same Business Question definitions instead of implementing separate analytics logic for each platform.

BQ5 has two separate responsibilities: runtime recommendation is provided by the shared PostgreSQL public.recommend_quests RPC, while the Analytics Engine reconstructs recommendation evidence from the emitted recommendation events.

3. Architectural Design

3.1 Class Diagram Flutter

Deployment Diagram

The deployment diagram shows where the system executes and how its runtime environments communicate. GitHub repositories are not represented as runtime services because they version the implementation rather than receive application requests.

Rationale

  • Separate mobile clients, shared backend: Kotlin and Flutter run independently on mobile devices and use the same Supabase backend contract. This supports platform-specific implementations without duplicating the operational database or shared backend logic.

  • Managed Supabase environment: Authentication, PostgREST, Storage and PostgreSQL are grouped within Supabase because they are managed backend services. Mobile clients access them through HTTPS rather than connecting directly to PostgreSQL with database credentials.

  • Shared recommendation logic: BQ5 is represented as the PostgreSQL RPC public.recommend_quests, accessed through PostgREST. This reflects the implemented solution and avoids incorrectly presenting it as a deployed Edge Function.

  • Local and remote photo evidence: The Android environment includes the camera and private application files because photo capture begins on the device. Remote evidence is stored in the private quest-proofs bucket, with per-step records and ownership-based policies. Keeping local evidence allows the quest flow to continue when upload fails, while exposing a manual retry.

  • Direct weather integration: Kotlin communicates directly with Open-Meteo through HTTPS. Weather acquisition belongs to the mobile context flow; the diagram therefore does not introduce an unimplemented backend weather service.

  • Separate analytics execution boundary: The Analytics Engine contains Python batch-processing code that connects to the shared PostgreSQL database through DATABASE_URL. Operational data and events belong to public, while analytics outputs belong to analytics; these are schemas in the same database, not separate databases.

  • Explicit implementation boundaries: Analytics execution hosting and scheduling are marked as unconfirmed. No dedicated server, scheduler, FCM, Google Maps or Kubernetes deployment is claimed. Flutter's shared-backend connection is documented, but its weather integration is not asserted without source verification.

Kotlin Class Diagram

The class diagram focuses on architecturally significant relationships rather than every class in the application. It is divided into three views: MVVM and repositories, context acquisition, and camera/Factory Method.

Rationale

  • MVVM-style presentation: Compose functions render application state and forward user actions to AppViewModel. The ViewModel coordinates application behavior and exposes observable StateFlow state. Lifecycle-aware collection allows the UI to react to state changes without implementing persistence or recommendation logic directly in the views.

  • Repository boundaries: Catalogue, quest progress, recommendations, analytics and photo-proof persistence have separate repository interfaces. AppViewModel depends directly on these interfaces, reflecting the actual code. Supabase implementations encapsulate remote access, while the catalogue also has an in-memory implementation.

  • Context Facade: ContextManager provides one readContext() operation over LocationProvider, WeatherProvider and TimeProvider. Consumers receive a unified UserContext instead of coordinating individual providers. This is Julián's documented Facade contribution.

  • Camera service boundary: CameraPhotoProofService isolates Android-specific URI and file-sharing behavior. ActiveQuestScreen launches the camera and reports captured evidence to the ViewModel, which coordinates upload through PhotoProofRepository.

  • Factory Method: PhotoProofFileFactory prepares the private directory and delegates file creation through createProof. JpegPhotoProofFileFactory creates a unique JPEG product exposed through PhotoProofFile. This separates file allocation from Android camera integration and permits file-creation tests without launching the camera. It is Factory Method rather than Abstract Factory because it creates one product abstraction, not families of related products.

  • Accurate UML relationships: Inheritance from an abstract class uses a solid line with a hollow triangle; interface realization uses a dashed line with a hollow triangle. SidequestsApp and ActiveQuestScreen are explicitly identified as Compose functions rather than Kotlin classes.

4. Implemented Features

4.1 Group

  • Analytics Pipeline
  • Backend: Supabase
Component / Feature Platform Main Responsibility
Shared Supabase backend Shared Team
Supabase Auth Kotlin / Flutter Mobile subgroups
Remote quest catalogue Kotlin / Flutter Mobile subgroups
Shared analytics event contract Shared Team

4.2 Individual

Lucas Mejía

  • Business Question Feature: Implemented BQ number 3 from the analytics pipeline. BQ3 was created as a session-level onboarding funnel analysis using the shared analytics_events table. A new event contract records each completed onboarding step with its order and name, implemented in Flutter for the “welcome” and “preferences” screens. The analytics query deduplicates step completions per session, calculates reach and drop-off between consecutive steps, and excludes the final step. Its results are stored as a versioned BQ3 entry in analytics.bq_results, allowing the dashboard to display the results without changes. The implementation was validated end-to-end using real onboarding sessions, including one abandoned after the first step, confirming that the “welcome” step produced a non-zero drop-off rate.

  • Design pattern and Architecture Tactic:

    • Cache Tactic (Availability): Implemented the cache tactic to maintain information availability in the app. Created the QuestRepository which uses a write-through cache to improve availability and resilience when the remote backend is unavailable. LocalDataSource stores structured quest data in Hive (sidequests_cache) and small flags in SharedPreferences. Whenever a remote fetch succeeds, the repository immediately updates the local cache (cacheQuestCatalog and cacheUserQuests), keeping it refreshed opportunistically rather than on a schedule. If the remote request fails, the repository returns the last cached copy instead of propagating the error. Since there is no TTL or invalidation mechanism, cached data remains until a successful fetch replaces it or LocalDataSource.clear() removes it on sign-out. The purpose of this tactic is to prioritize availability and offline resilience over strict data freshness.
    • Repository Pattern: Implemented the Repository Pattern to separate ViewModels from the details of data access. AuthRepository, ProfileRepository, QuestRepository, and SocialRepository sit between the ViewModels and the remote SupabaseRemoteDataSource and local LocalDataSource, which are injected through app.dart. ViewModels therefore interact with domain-level methods such as getCatalog() and signUp() without depending directly on Supabase, Hive, or other storage technologies. Repositories also translate backend-specific exceptions such as PostgrestException and AuthException into the common AppException type. The purpose of this pattern is to centralize data access and error handling while decoupling the rest of the application from specific backend and storage implementations.
  • Views Implemented

    • Explore Page: Implemented and connected to the recommendation engine.
    • Near Me Map: Implemented and connected to the proximity smart feature to list location-based sidequests near the user.
    • Onboarding Page: Implemented with questionnaires for capturing initial user preferences.
  • Features

  • a) Compass pointing toward the mission. On a mission with coordinates, the detail screen shows a compass arrow pointing toward the destination and the remaining distance. It combines the user’s location with the mission coordinates to calculate the bearing and distance, then rotates the arrow relative to the phone’s compass heading. If location or compass data is unavailable, it shows an activation prompt or a fallback message. QuestCompass · QuestDetailView

  • b) BQ6 abandonment analytics. When a user abandons a mission, the quest_abandoned event now includes the mission’s estimated cost, the current mission step, and the distance to the mission in meters. The ViewModel supplies the cost, coordinates, and step; the analytics tracker calculates the distance from the latest location snapshot and serializes these fields for the analytics event. Distance is omitted if either location is unavailable. QuestViewModel · AnalyticsTracker · AnalyticsEvent

  • c) Phone-context banner. The app shell displays a banner when the phone is offline or its battery is low. A view model listens for connectivity and battery changes, treating 20% or less as low battery; the banner then explains that missions cannot load offline or that GPS use is reduced to conserve power. If both conditions apply, the offline message takes precedence. ContextStatusViewModel · ContextBanner

  • d) Smart geolocation. Mission check-ins adapt GPS precision and update frequency according to how close the user is to the destination and the phone’s battery level. While far away, location sampling is less precise and less frequent; within 300 meters, it switches to precise GPS. Low battery reduces sampling where possible, and a 100-meter hysteresis margin helps avoid repeated mode changes caused by GPS fluctuations. LocationCheckInService · check_in_sampling

  • e) Change password from Profile. A lock button in the Profile opens a dialog where the user enters and confirms a new password. The form checks that it is at least six characters and that both entries match, then sends the update through the auth ViewModel and repository to Supabase. Errors appear in the dialog; success closes it and displays a confirmation message. ProfileView · Change password dialog · AuthRepository

  • f) Mission address using OpenStreetMap Nominatim. For missions with coordinates, the detail view requests a human-readable address from Nominatim’s reverse-geocoding endpoint and displays the returned address. The request specifies Spanish and an identifying User-Agent; if the mission has no coordinates or the lookup fails or times out, the address is hidden. QuestAddress · ReverseGeocodingService

Alejandro Pardo

  • Business Question Feature:

    • BQ8 – Recommendation Diversity (Type 3): How does increasing the diversity of Side-Quest recommendations affect acceptance and return rates among users who have already completed multiple Side-Quests? Implemented as a server-side A/B experiment on top of the shared BQ5 recommendation RPC. Migration 008 extends recommend_quests with two variants: control (original BQ5 ranking) and diverse (same score, minus a novelty penalty for quests shown to the user in the last 7 days and a penalty for repeating a category inside the same list). The variant is assigned per user with a hash of auth.uid(), so each user always sees the same arm, and both the Kotlin and Flutter apps use it without implementing the experiment themselves. Flutter copies variant, rank and batch_id into the metadata of recommendation_shown events. The analytics query compares both variants per week using category diversity per list, normalized category entropy, repeat exposure, and acceptance rate as a guardrail (diversity should not reduce acceptance). The bq8 pipeline job stores the result as a BQ8 entry in analytics.bq_results, and it was validated end-to-end with real events (3 rows stored).
  • Design pattern and Architecture Tactics:

    • Adapter Pattern: WeatherService adapts the Open-Meteo API to the app's domain model WeatherSnapshot. It is the only class that knows Open-Meteo's JSON format; the rest of the app (ContextManager, QuestViewModel, views) only works with WeatherSnapshot. If the weather provider changes, only the adapter has to be modified.
    • Cache with TTL Tactic (Performance): WeatherService keeps an in-memory cache keyed by coordinates rounded to 2 decimals (~1 km) with a 15-minute TTL. This matters because ContextManager.snapshot() runs on every analytics event; without the cache, each event would trigger a network request. Unlike the write-through cache in QuestRepository (no TTL, prioritizes availability), this cache prioritizes performance and expires, because weather data becomes outdated quickly.
    • Timeout + Graceful Degradation Tactic (Availability): Weather requests have a 5-second timeout and WeatherService.fetch() never throws: on any failure it returns the last cached value or null. The UI hides the weather card and Explore keeps working with time-of-day context only, so an external-service failure never blocks the app.
    • Architectural Pattern Contribution (MVVM + Repository): Extended every layer for the quest rating flow: QuestCompletedView (View) → QuestViewModel.submitRating() (ViewModel) → QuestRepository.rateQuest() (Repository, translates PostgrestException into AppException) → SupabaseRemoteDataSource.rateUserQuest() → user_quests table in Supabase.
  • Views Implemented:

    • QuestCompletedView: Shown after the last step of a quest. The user rates the quest (1–5 stars, required) and selects feedback tags; the rating and tags are stored in user_quests in Supabase. It also shows the "You might like" recommendations.
    • BiometricLockView: Shown on app start when the user has an active session and biometric unlock enabled. It asks for fingerprint authentication before opening the app, with a "Use password" fallback.
    • Contributions to existing views: rain/night banner and "Start now" button in ExploreView (created by Lucas Mejía), "Weather at the location" card in QuestDetailView, and the biometric unlock switch in ProfileView.
  • Functionalities:

Item Functionality How it works
a. Sensor Shake for a Surprise Quest ShakeDetector listens to the accelerometer (userAccelerometerEvents, gravity removed). When the magnitude exceeds 15 m/s² (2-second debounce), Explore picks a random available quest that fits the selected time and opens its detail.
b. Type 2 BQ Instant Plan – "Start now" (BQ4) Starts a recommended quest in one tap and measures time and interactions to start, answering BQ4 by comparing instant_plan vs standard starts.
c. Context-aware Context-Aware Explore ContextManager captures weather and time of day. When it is raining or nighttime, Explore automatically moves anywhere (indoor) quests to the top, without hiding the rest, and shows a banner explaining why. No user action is required. The weather code is also stored in analytics events.
d. Smart feature You Might Like SimilarQuestRecommender scores the catalog against the completed quest: +3 same category, +1 per shared tag, +2 similar duration (≤15 min difference), +1 same difficulty. It excludes quests already completed or in progress. If the rating is ≤2, same category becomes −3, so suggestions adapt to the user's feedback.
e. Authentication Biometric Unlock Optional fingerprint unlock using local_auth through BiometricService. Enabled from Profile settings; on app start, AuthGate requires the fingerprint before opening the app. If it fails, the user can sign in with their password.
f. External service Weather at the Quest Location Uses the Open-Meteo API to show current temperature, conditions and rain probability for the next hours at the quest location (or the user's location for anywhere quests).

Julián Contreras

  • Business Question Feature: Implemented BQ9 (Quest Category Performance, Type 3) in the analytics pipeline. The query computes, per category, the quests accepted in the last 30 days, how many were completed and the completion rate, ordered from lowest to highest. The bq9 pipeline job stores the result in analytics.bq_results.

  • Design pattern and Architecture Tactic:

    • Strategy Pattern: Implemented step verification as interchangeable strategies (NoVerification, LocationVerification, PhotoVerification, CompositeVerification) behind StepVerificationStrategy, selected from each step's verification_type.
    • Retry Tactic (Availability): Photo proofs are stored locally before uploading and kept for "Reintentar subida" when the upload fails for a retryable reason.
    • MVVM contribution: Created StatsViewModel and extended QuestViewModel, AuthViewModel, QuestRepository, AuthRepository and the remote/local data sources, keeping views free of direct Supabase access.
  • Views Implemented

    • Mis estadísticas (StatsView): Opened from Profile. Shows completed quests, the user's completion rate per category and the steps walked during missions.
    • Login with email code (OtpLoginView): Two-state screen (email, then 6-digit code) with a 60-second resend cooldown.
    • Mission tab verification controls: Live step counter, automatic check-in state and photo capture/retry for the current step.
  • Functionality

    • (a) Sensor — Mission pedometer: Uses the phone's step counter (pedometer, with runtime permission through permission_handler) while a quest is active. The steps walked in each attempt are saved locally and shown in the Mission tab and in "Mis estadísticas". Devices without a step counter or with the permission denied can still use the app.
    • (b) Type 2 BQ — "¿Cómo te sientes hoy?" (answers BQ5): Chips in Explore ("Solo yo", "Con alguien", "En grupo") override the profile's social level for the current session only and reload the top 3 from recommend_quests. recommendation_shown records social_level_source (session or profile) so the analytics engine can tell both cases apart.
    • (c) Context-aware — Automatic location check-in: While a quest is active, the app listens to the location and verifies a location step automatically when the user is within 50 m of the quest (with a GPS accuracy of 75 m or better). Sampling adapts to battery level and distance, and quests without coordinates do not require location verification.
    • (d) Smart feature — "Probabilidad de que la termines": Each quest card in Explore shows High / Medium / Low / New for you, based on the user's own completion rate in that category (High ≥ 70 %, Medium ≥ 40 %, and "New for you" with fewer than 3 attempts). It is the user-level version of BQ9.
    • (e) Authentication — Login with email code: Passwordless sign-in with a 6-digit code sent by Supabase Auth (signInWithOtp without creating new users, then verifyOTP).
    • (f) External service connected to the backend — Photo proof: Steps that require a photo use the camera (image_picker, JPEG, max 1600 px, quality 70). The photo is uploaded to the private quest-proofs bucket in Supabase Storage following the backend path contract, registered in quest_photo_proofs and tracked with the photo_proof_uploaded event, the same contract used by the Kotlin app.

Sebastián Maldonado

  • Business Question Feature: Implemented BQ number 5 from the analytics pipeline. BQ5 provides up to three personalized Side-Quest recommendations for the current session based on information such as the user's available time, interests, preferred social interaction level and previous recommendation interactions. The recommendation logic is shared through the Supabase public.recommend_quests PostgreSQL RPC instead of being duplicated in the mobile client. The Kotlin application consumes the recommendation results and emits recommendation_shown events. The Analytics Engine includes a BQ5-specific query and pipeline job that reconstructs the latest recommendation batch and stores the resulting evidence in analytics.bq_results. The functionality was validated end-to-end from the Kotlin application by changing time and interest filters and by verifying that Not for me removes a quest from Smart Picks and requests another recommendation when possible.

  • Design pattern and Architecture Tactic:

    • Graceful Degradation / Fallback Tactic (Availability): Contributed to the availability behavior of the Smart Picks and contextual recommendation flow. When the shared recommendation service or optional contextual information is unavailable, the Kotlin application can continue operating using fallback behavior instead of failing the entire Explore experience. Context acquisition also treats location and weather as optional information, allowing the recommendation experience to continue when those sources are unavailable. The purpose of this tactic is to preserve application availability when a remote dependency, permission or contextual source cannot provide data.
    • Observer Pattern: Implemented an Observer-style reactive UI flow using Kotlin StateFlow and Jetpack Compose. AppViewModel exposes observable application state and the Compose UI collects that state using lifecycle-aware observation. When the ViewModel changes the application state, the observing UI receives the new state and recomposes the affected elements. This decouples state mutation from UI rendering and keeps recommendation, authentication and context state outside the UI components.
  • Views Implemented

    • Explore / Smart Picks Page: Contributed to the Kotlin Explore experience used to display personalized Smart Picks. The view allows users to modify available time, interests and location mode and immediately refreshes the recommendation result. It also exposes the Not for me interaction so users can reject recommendations while maintaining control over the experience.
  • Functionality

    • Sensor Feature: Contributed to the camera-based photo-proof functionality by implementing the domain-level completion policy for photo-required quest steps. A step that requires photographic evidence cannot be completed until a valid local photo proof has been captured. The integrated functionality was validated using the Android Studio emulator and the shared Supabase Storage backend.
    • BQ Type 2 Feature: Implemented BQ5 Smart Picks. The feature consumes the shared backend recommendation RPC and displays up to three relevant Side-Quests for the current session.
    • Context-Aware Feature: Integrated contextual evidence into the BQ5 recommendation flow. Recommendation events record information such as time of day, location availability, weather availability and whether contextual fallback was required.
    • Smart Feature: Implemented the Smart Picks personalized recommendation experience. Recommendations react to user preferences, current filters and previous recommendation interactions instead of presenting only a static quest catalogue.
    • Authentication: Contributed to the Kotlin integration with Supabase Auth. The implemented flow supports account creation, sign-in and sign-out and was validated from the Android application.
    • External Service: Integrated the Open-Meteo context result and fallback state into the BQ5 recommendation evidence flow. The integrated application was validated displaying real weather information while continuing to operate when optional contextual information was unavailable.
  • Architectural Pattern Contribution:

    • MVVM-style reactive presentation: Contributed to the Kotlin presentation architecture through the Explore / Smart Picks flow. The Compose UI observes state exposed by AppViewModel, while recommendation, analytics and backend access are delegated to repositories and services instead of being implemented directly inside the view layer.

Lex

  • Business Question Feature:

    Implemented the Kotlin-side functionality supporting BQ6: Quest Abandonment Reasons, classified as a Type 2 business question: “What are the most frequent reasons users select when abandoning an active Side-Quest, and how do these reasons vary according to the quest's estimated duration, cost and distance?”

    The abandonment flow requires a selected reason and persists its stable code in user_quests.abandon_reason. It also emits a quest_abandoned event containing the reason, attempt identifier, estimated duration, estimated cost, normalized catalogue distance when available, progress information and photo-proof indicators. Supported reasons include running out of time, excessive distance or cost, unavailable places, difficulty, weather or mood changes, and other reasons.

    Saving progress is recorded separately and is not treated as abandonment. This contribution provides the source evidence needed for BQ6 analysis; end-to-end validation of the aggregated analytics answer remains pending.

  • Design Pattern and Architecture Tactic:

    • Factory Method: Implemented Factory Method in the actual camera capture flow. PhotoProofFileFactory is the abstract creator, and its protected createProof method delegates product creation to JpegPhotoProofFileFactory. The resulting file is exposed through the PhotoProofFile interface and consumed by CameraPhotoProofService. This separates JPEG file creation from Android camera and URI handling. Each capture receives a unique file, preventing retakes from overwriting previous evidence. This implementation is independent of AppViewModelFactory and is covered by unit tests.

    • Graceful Degradation / Local Fallback Tactic (Availability): Implemented local-first photo proof. A valid local capture allows users to continue a photo-required step even when remote upload fails. The application preserves the local evidence, distinguishes local capture from successful upload, and exposes Retry upload. This reduces the impact of network or Storage failures without incorrectly reporting that the proof was uploaded.

  • Views Implemented:

    • Active Quest Screen: Integrated camera capture into the real Jetpack Compose quest screen. Photo-required steps expose capture controls and display uploading, locally captured, successfully uploaded and upload-error states. The screen also provides Retry upload and step-completion controls.

    • Exit Flow Screen: Integrated abandonment-reason selection and distinct actions for Save progress & exit, Keep going, and Start another quest instead. Abandonment requires a selected reason, while saving progress preserves the active attempt.

  • Functionality:

    • A — Sensor Feature: Camera / Photo Proof: Integrated the device camera to capture JPEG evidence associated with a specific quest attempt and step. The application stores the capture locally and exposes its capture and upload status in the Active Quest screen. The Kotlin team reported successful Android verification after the shared Storage backend was provisioned.

    • B — Type 2 Business Question: BQ6: Implemented mandatory abandonment-reason selection, persistence and analytics instrumentation. Abandonment events provide the reason, estimated duration, estimated cost and catalogue distance when available, supporting comparisons across those dimensions. The data-collection functionality is implemented; validation of the aggregated analytics answer remains pending.

    • F — External Service: Supabase Storage: Integrated photo-proof upload with the shared Supabase Storage service, independently of authentication. The application uploads the JPEG to the private quest-proofs bucket and registers it in quest_photo_proofs. Success is reported only after both operations complete.

    • Additional Functionality — Quest Lifecycle: Contributed to quest acceptance, step progress, completion and abandonment persistence. Saving progress keeps the attempt active; abandonment stores the selected reason and clears the active attempt locally. Accepting the quest again creates a new attempt identifier.

    • Additional Functionality — Photo-Proof Analytics: Added photo_proof_captured, photo_proof_uploaded and photo_proof_upload_failed events. Analytics records technical metadata rather than image contents or public image URLs.

  • Architectural Pattern Contribution:

    • MVVM and Repository Separation: Contributed to the photo-proof and quest-lifecycle flow by keeping Compose rendering in the UI, state coordination in AppViewModel, persistence in repositories, and Android camera integration in a dedicated service. File creation is delegated to the Factory Method implementation.

    • Private Evidence Storage: Added backend migration 009_quest_photo_proofs.sql, creating the private bucket, per-step proof records and ownership-based RLS policies. Access is scoped to the authenticated user's folder and owned quest attempts.

Julian

  • Business Question Feature:

    Implemented the Kotlin-side functionality supporting BQ10: Location-Independent Mode Usage, classified as a Type 2 business question, and also contributed to the existing BQ5: Personalized Quest Recommendation functionality. For BQ5, I contributed to the personalized recommendation flow that selects quests based on the user's information and recommendation criteria. This functionality was later extended with contextual information for BQ10, allowing the recommendation flow to also consider location, time of day and weather. For BQ10, the application distinguishes between location-based and location-independent recommendation modes. It emits "location_independent_mode_selected" when the user selects the location-independent mode and "location_based_mode_selected" when the GPS-based mode is selected. These events include "location_mode", "time_of_day" and "weather_condition", providing the context required for the BQ10 analysis. The analytics implementation groups usage by session and context and stores the BQ10 result in "analytics.bq_results". The final validation against the live Supabase database remains pending.

  • Design Pattern and Architecture Tactic:

    • Facade: Implemented the Facade pattern through "ContextManager". The "ContextManager" provides a single "readContext()" operation that hides the details of obtaining the device location, retrieving weather information and determining the current time of day. This keeps the recommendation flow from having to coordinate the different context providers directly.
    • Information Hiding / Encapsulation: Kept the location, weather and time-of-day logic behind their corresponding abstractions ("LocationProvider", "WeatherProvider" and "TimeProvider"). This reduces the dependency between the recommendation functionality and the individual context sources.
  • Views Implemented:

    • Context-Aware Discover / Explorer View: Integrated the context-aware recommendation functionality into the Discover/Explorer flow. The view can use the current context when displaying personalized quest recommendations.
    • Personalized Recommendation Flow: Contributed to the recommendation flow used by BQ5 and extended it with contextual information for BQ10.
  • Functionality:

    • A — Sensor Feature: GPS / Device Location: Integrated the device location as a context source for the recommendation system. The current location is obtained through "LocationProvider" and handled by "ContextManager", without exposing the location implementation directly to the rest of the application.
    • B — Type 2 Business Question: BQ5 — Personalized Quest Recommendation: Contributed to the implementation of the personalized quest recommendation functionality. The recommendation flow uses the available user and quest information to provide personalized quest suggestions. This functionality serves as the base for the later context-aware extension.
    • B — Type 2 Business Question: BQ10 — Location-Independent Mode Usage: Implemented the data collection and analytics instrumentation required to measure the use of location-independent mode. The events distinguish between "anywhere" and "gps" usage and include contextual information such as time of day and weather condition.
    • Additional Functionality — Context-Aware Feature: Contributed to the context-aware functionality by combining location, time of day and weather as inputs for the recommendation flow. The context is collected through "ContextManager" and exposed as a single "UserContext".
    • F — External Service: Open-Meteo Weather API: Integrated weather information through "WeatherProvider", using the user's current coordinates to obtain the relevant weather context from Open-Meteo. The external API details remain behind the provider abstraction.
    • Authentication — Supabase Auth: Contributed to the authentication flow using Supabase Auth through the "AuthRepository" abstraction. The implementation supports user registration, login, logout and session-state handling without coupling the presentation layer directly to the authentication service.
  • Architectural Pattern Contribution:

    • Facade and Context Separation: "ContextManager" acts as the main entry point for obtaining contextual information. It coordinates "LocationProvider", "WeatherProvider" and "TimeProvider", keeping the recommendation flow independent from the details of each context source.
    • MVVM and Repository Separation: The context-aware functionality follows the existing application architecture, with the UI responsible for presentation, "AppViewModel" coordinating application state and repositories handling data access. The context functionality is exposed through "ContextManager" instead of being handled directly by the UI.
    • Context Provider Abstraction: The use of "LocationProvider", "WeatherProvider" and "TimeProvider" separates the individual context sources from the feature that consumes them. This supports the information-hiding tactic and allows the underlying implementations to change without modifying the recommendation flow.

Ethics video

https://drive.google.com/file/d/1O8Jd-bydSFchPu0H_FQzYlBHGl3X030I/view?usp=sharing