S2: Final Deriverable - ISIS3510-202510-T14/Documentation GitHub Wiki

Table of Contents

  1. Business Questions (BQs)

  2. Analytics Pipeline (AP)

  3. Architectural Design (AD)

  4. List of Implemented Features (IF)

  5. Ethics Component


Attention: you need to place link in the android\app path of the mobile repo for it to work

Work Distribution

Backend

Sebastián

  • Readme Creation
  • Hotfixes
  • Real-Time Event Processor
  • Implement Unified API Layer (API Gateway)
  • Bet Management Module

Federico

  • Hotfix of multiple stuff
  • Fix Location Processor Event Filtering & Incident Recording
  • Fixes: Missing 'created_at' and 'updated_at' Fields in read_record Output
  • ACID Database (PostgreSQL)
  • Real-Time Database (MongoDB)
  • Location/Time-Based Event Processor
  • Sports Data Integration Module

David

  • User Management Module
  • Analytics & Recommendation Engine

Frontend

David

  • Hotfix: User Authentication Flow
  • Signup View
  • Login View
  • General: Connect Flutter project to Firebase

Federico

  • Hotfix: Missing import
  • Matches View enhancements
  • Connect Matches View to Backend API
  • Sport Event Proximity Notification View (BQ)
  • Sport Event Attendance Notification View (BQ)
  • Feature Matches View: Matches listing

Sebastian

  • Place Bet View
  • Nav Bar

1. Business Questions (BQs)

Business Question If Yes, Then... Question Type & Rationale
Does the user seem to be at a university sports venue during a game? Show a real-time betting prompt on their screen for the ongoing match with quick bet and reporting options. Type 2: Increases engagement by providing real-time betting opportunities tailored to the user's situation.
Does the user seem to be near a university sports event? Make a pop-up notification appear on their phone letting them know about the event that is taking place nearby. Type 2: Enhances the user's experience by providing timely and relevant information based on their location.
Has the user placed multiple bets on the same team recently? Recommend related bets in a prompt on their screen. Type 2: Offers personalized suggestions that enhance user experience and encourage continued engagement.

2. Analytics Pipeline (AP)


1. Measuring Real-Time User Attendance at University Sports Events

Reframed BQ:

“What is the most effective way to leverage real-time user location data to accurately quantify live attendance at university sports events, enabling targeted engagement strategies such as real-time betting promotions?”

Analytics Pipeline Focus

  • Ingestion:
    • Continuously collect real-time GPS coordinates or beacon data from mobile devices of active users.
  • Processing:
    • Compare incoming user location data against geofenced sports venue maps.
    • Verify event status through integration with external sports event calendars.
    • Identify and confirm user presence within active event zones (isAtGame = true).
  • Storage:
    • Store attendance confirmation data per event (e.g., total attendee count, individual attendance statuses) in a real-time database for immediate retrieval and analysis.
  • Insights for the Analytics Persona:
    • Empowers product managers and marketing analysts with immediate visibility into real-time attendance, enabling optimized, location-specific promotional activities.

End-user Trigger:

  • Real-time betting prompts or contextual notifications triggered directly to users identified as present at live events.

2. Evaluating Proximity-to-Attendance Conversion at University Sports Events

Reframed BQ:

“How can the business continuously track and analyze user proximity to university sports venues, measure conversion rates from proximity to actual event attendance, and use these insights to enhance the effectiveness of location-based promotional notifications?”

Analytics Pipeline Focus

  • Ingestion:
    • Continuously ingest streaming GPS location data from mobile app users.
    • Retrieve upcoming event details (location, date, and time) from an integrated sports events database.
  • Processing:
    • Apply geospatial algorithms to detect users crossing predefined proximity thresholds (e.g., within 500 meters) around sports venues.
    • Monitor subsequent user movements to validate attendance within event geofences during scheduled event times.
    • Calculate the conversion rate of users transitioning from "near-event" status to confirmed attendees.
  • Storage:
    • Persist proximity detection and attendance confirmation events, along with calculated conversion metrics, in structured analytics storage.
  • Insights for the Analytics Persona:
    • Allows business stakeholders to measure and optimize the effectiveness of proximity-based marketing initiatives, enhancing targeted engagement and maximizing attendance conversions.

End-user Trigger:

  • Immediate, relevant notifications prompting users who enter proximity zones to attend events or engage with event-specific promotions, including betting opportunities.

3. Identifying Users Who Have Placed Multiple Bets on the Same Team

Reframed BQ:

“How can we merge recent betting transactions, ingest user betting history, and analyze repeated bets on the same team to store a ‘loyalty to team X’ score, which can drive personalized bet recommendations?”

Analytics Pipeline Focus

  • Ingestion:
    • Capture betting transaction logs in real-time from the app or betting platform.
    • Include metadata: team ID, bet amount, bet outcomes, timestamps.
  • Processing:
    • Aggregate the number of times a user has bet on each team within a defined window (e.g., last 30 days).
    • Calculate a “loyalty index” or repeated-bet score.
  • Storage:
    • Persist these loyalty scores in a user profile database for quick lookup.
    • Maintain historical trend data in a warehouse for deeper analytics (e.g., loyalty changes over time).
  • Insights for the Analytics Persona:
    • Marketers or product managers can see which teams are trending among heavy bettors, enabling targeted promotions.
    • Identify high-loyalty segments for specialized campaigns.

End-user Trigger:

  • When the “loyalty index” passes a threshold, prompt the user with related bet offers or suggestions during their next session.

4. AP Design

ap

Explanation:

  1. Data Ingestion: The engine begins by ingesting data from both the Real-Time Database and the ACID Database. This step ensures that the latest user interactions, event logs, and transactional records are available for analysis.

  2. Processing Steps:

    • Recommendation Calculation: Utilizing historical betting data and information on upcoming events, the engine computes personalized bet recommendations for users.
    • Metrics Computation: By analyzing logged incidents from the "Location/Time-Based Event Processor," the engine calculates key metrics such as the conversion rate (the percentage of users who were near and eventually attended sports events) and the total number of attendees at each event.
  3. Outputs: The results from the processing steps—recommended bets and computed metrics—are stored back into the Real-Time Database. This allows other system components and the mobile app to access and utilize this information in real-time.

Rationale:

  • Batch Processing: The engine operates as a scheduled task, likely running daily during off-peak hours (e.g., late night, Colombian time). This approach ensures that resource-intensive computations do not interfere with peak user activity periods.

  • Data Integration: By aggregating data from both the Real-Time and ACID Databases, the engine can perform comprehensive analyses that consider both real-time user interactions and historical transactional data.

  • Real-Time Updates: Storing the outputs back into the Real-Time Database facilitates immediate access for other system components and the mobile app, ensuring that users receive up-to-date recommendations and insights.

Connections:

  • Input Sources: The engine connects to the Real-Time Database and the ACID Database to retrieve necessary data for processing.

  • Output Destination: Processed results are written back to the Real-Time Database, making them accessible to components like the "Bet Management Module" and the mobile app.

  • Interaction with Other Modules: While the engine primarily interacts with the databases, its outputs influence various system components, including user interfaces and notification services, by providing the data needed for personalized user experiences.


3. Architectural Design (AD)


3.1 Viewpoints

Below is the diagram representing the software viewpoints architecture we intend to define:

viewpoints

Note: The Concurrency, Operation, Deployment and Development viewpoints are intentionally omitted in this documentation.


3.2 Context Diagram

The context diagram shows the Sports Betting MVP system and its external interactions at a high level.

context_diagram

Central Component

  • Sports Betting MVP: Core system, central node for all connections.

External Entities and Connections

  1. End User: Bets and gets prompts—bidirectional link.
  2. Auth Provider: Authenticates users—sends validation data.
  3. Mobile OS Location Services: Gives location data—sends GPS/geofence info.
  4. University Sports Calendar: Provides event schedules—sends game data.
  5. Odds Feed: Supplies betting odds—sends real-time odds.
  6. Analytics Pipeline: Processes data, sends insights—bidirectional link.

3.3 Functional Diagram

Each component and its rationale will be explained in section 3.5. functional


3.4 Data Model

The core design splits data across two databases:

  1. ACID Database (SQL) — Uses PostgreSQL.
  2. NoSQL Database (Near-Real-Time / Non-Relational) — Uses MongoDB.

This section describes table schemas (PostgreSQL) and collection schemas (MongoDB) along with their relationships.


ACID Database (PostgreSQL)

1. user Table

Stores core user profile and balance data for betting transactions.

Column Type Constraints Description
user_id UUID (or VARCHAR) PK Unique identifier for the user in the ACID DB.
email VARCHAR(...) UNIQUE User’s email address (if needed for contact).
phone VARCHAR(...) (Optional) Phone number, if relevant.
name VARCHAR(...) (Optional) Display name or full name.
balance DECIMAL(...) DEFAULT 0 Tracks the user’s funds for betting (if an internal wallet is required).
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP Timestamp when the user record was created.
updated_at TIMESTAMP On update CURRENT_TIMESTAMP Timestamp when the record was last updated.

Note on Authentication:

  • Previously, we might have stored the Firebase Auth uid in this table. Now, we could store an External Auth Service ID or use our Django-based authentication’s primary key here.
  • Some implementations prefer to keep a separate column for the external ID, especially if it is neccessary to keep the internal user_id distinct from any third-party auth identifiers.

2. event Table

Maintains a minimal event record to support transactional integrity for bets, even if detailed real-time data is stored elsewhere (in MongoDB). This ensures bets always reference a valid event in the SQL database.

Column Type Constraints Description
event_id UUID (or VARCHAR) PK Unique event identifier in ACID DB.
rt_event_id VARCHAR(...) (Optional, recommended) A pointer or reference that correlates to the MongoDB _id if the real-time DB needs it.
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP Timestamp when the row was created.

Note:

  • Keep only the critical fields needed for bets and other ACID operations.
  • Detailed, rapidly changing data (e.g. scores, “live” status) can reside in MongoDB.
  • The column rt_event_id helps tie back to the corresponding document in the MongoDB events collection.

3. bet Table

Stores transactional betting records, ensuring ACID properties (e.g., fund reservation, bet placement, status updates, etc.).

Column Type Constraints Description
bet_id UUID (or VARCHAR) PK Unique identifier for the bet.
user_id UUID (or VARCHAR) FKuser(user_id) Links to the user who placed the bet.
event_id UUID (or VARCHAR) FKevent(event_id) Links to the event on which the bet was placed.
stake DECIMAL(...) NOT NULL Amount wagered by the user.
odds DECIMAL(...) NOT NULL Odds at the moment of bet placement (could be stored as decimal).
status VARCHAR(...) DEFAULT 'placed' Current bet status: e.g., placed, won, lost, canceled.
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP Timestamp when the bet was placed.
updated_at TIMESTAMP On update CURRENT_TIMESTAMP Timestamp when the bet was last updated.

NoSQL Database (MongoDB)

Database Structure

Instead of a single Firebase RTDB hierarchy, we now use MongoDB collections. Below is an example logical structure mirroring our previous nodes:

  1. events collection
  2. recommendedBets collection
  3. incidents collection (with subtypes or separate collections for proximity vs. attendance)
  4. analytics collection

For each collection, we store documents with references to the SQL data (e.g., user IDs, event IDs) to maintain relationship consistency.

Note:

  • We may choose separate collections for proximity vs. attendance incidents, or use one collection with a type field.
  • Document _id in MongoDB can be an ObjectId, a UUID, or any unique string.

1. events Collection

Stores real-time or frequently updated details about sporting events (e.g., location, live status, dynamic odds, etc.). Each MongoDB document might look like:

{
  "_id": "<eventId>",        // Could be a UUID or ObjectId
  "acidEventId": "...",      // References event.event_id in PostgreSQL
  "name": "Team A vs Team B",
  "sport": "soccer",         // e.g. "soccer", "basketball", etc.
  "location": {
    "lat": 123.456,
    "lng": 78.910
  },
  "startTime": "2025-03-19T20:00:00Z",
  "status": "upcoming",      // e.g., "upcoming", "live", "ended"
  "providerId": "...",       // matches event.provider_id in ACID DB
  // Additional fields from the sports data feed as needed
  "updatedAt": "2025-03-19T19:00:00Z",
  "team1:" "Los Andes",
  "team2:" "La javeriana"
}
  • The field acidEventId links back to the event table’s primary key (event_id), ensuring the ACID DB and MongoDB remain in sync.
  • The field _id in MongoDB can match the rt_event_id in the PostgreSQL event table if we want a consistent ID across both databases.

2. recommendedBets Collection

Stores per-user recommended bets. The Analytics & Recommendation Engine writes to this collection so the mobile app (or other modules) can read and display suggestions in near real time.

A document could look like:

{
  "_id": "<recommendationId>",
  "userId": "<userId>",      // Matches user.user_id in PostgreSQL
  "eventId": "<eventId>",    // Matches events._id in MongoDB
  "betType": "win",          // e.g. "win", "over/under", "handicap", etc.
  "description": "Team A is likely to win based on performance...",
  "createdAt": "2025-03-19T01:23:45Z"
}
  • Previously in Firebase, we might have nested recommendations under /recommendedBets/<userId>/...; in MongoDB, we can either keep them in a single collection (with a userId field) or store them in a sub-collection per user.
  • This structure supports easy querying (e.g., find({ userId: <someUserId> })).

3. incidents Collection(s)

Logs user proximity and attendance incidents. These are created by the Location/Time-Based Event Processor when it detects relevant spatiotemporal events.

We may store proximity and attendance in separate collections or use a single incidents collection with a type field:

Option A: Single Collection

{
  "_id": "<incidentId>",
  "type": "proximity",         // or "attendance"
  "userId": "<userId>",
  "eventId": "<eventId>",
  "timestamp": "2025-03-19T18:30:00Z",
  // ... any additional location/time data if relevant
}

Option B: Separate Collections

  • incidents_proximity
  • incidents_attendance

Each would have the same fields (minus the type), e.g.:

// incidents_proximity
{
  "_id": "<incidentId>",
  "userId": "<userId>",
  "eventId": "<eventId>",
  "timestamp": "2025-03-19T18:30:00Z"
  // ...
}

// incidents_attendance
{
  "_id": "<incidentId>",
  "userId": "<userId>",
  "eventId": "<eventId>",
  "timestamp": "2025-03-19T18:45:00Z"
  // ...
}
  • The userId corresponds to user.user_id in PostgreSQL.
  • The eventId corresponds to the _id in the MongoDB events collection.
  • We could also store a direct reference to acidEventId if we prefer referencing the SQL row.

4. analytics Collection

Holds aggregated metrics, such as daily or per-event conversion rates, total attendance, or any other computed KPI from the Analytics & Recommendation Engine. A typical document might be:

{
  "_id": "<metricId>",
  "type": "conversionRate",    // e.g. "conversionRate", "attendanceCount", etc.
  "eventId": "<eventId>",      // or could reference userId, or be a global metric
  "value": 0.42,               // numeric value for the metric
  "timestamp": "2025-03-20T02:00:00Z"
  // ... other dimensions/fields as needed
}
  • This closely parallels what we had under analytics/metrics in Firebase.
  • For more complex analytics, we might have multiple documents per date, event, or user segmentation.

Explanation / Relationships

  1. Events

    • PostgreSQL: Minimal fields in event table (event_id, name, start_time…).
    • MongoDB: Full or frequently updated fields in events collection (status, location, providerId, etc.).
    • A document’s _id in events can map to rt_event_id in SQL for cross-referencing.
  2. Recommended Bets

    • MongoDB: recommendedBets collection references userId (PostgreSQL user.user_id) and eventId (MongoDB events._id).
    • Populated by the Analytics & Recommendation Engine.
    • Read by the Bet Management Module or the mobile app for user-facing recommendations.
  3. Incidents (Proximity / Attendance)

    • Logged in MongoDB by the Location/Time-Based Event Processor.
    • Each record references userId (matching the PostgreSQL user) and eventId (matching the MongoDB event document).
    • Additional data can be included (GPS coordinates, timestamps, etc.).
  4. Analytics

    • Aggregated metrics stored in MongoDB.
    • Each metric references either an event (eventId), a user (userId), or a global dimension.
    • Used for reporting, insights, or additional recommendation logic.
  5. User Identifiers

    • Our primary user ID resides in PostgreSQL (user.user_id).
    • For external authentication, store an additional field (if needed).
    • In MongoDB documents, store userId that references the primary key from the SQL table.

Additional Considerations

  • UUIDs vs. ObjectIds:

    • In PostgreSQL, we can use UUIDs (native type) or strings as primary keys.
    • In MongoDB, the default _id is an ObjectId, but we can override it with a UUID or string if we want consistency across databases.
  • Real-Time Features:

    • While Firebase RTDB offered built-in real-time listeners, we can achieve near-real-time updates using MongoDB Change Streams, Pub/Sub messaging, or WebSockets integrated with Django Channels or a separate real-time service.
  • Security & Access Control:

    • Instead of Firebase Security Rules, we’ll rely on Django’s authentication/authorization and possibly MongoDB’s access controls.
    • API endpoints in our Django monolith handle read/write logic to both databases, ensuring consistent security policies.
  • Backward Compatibility:

    • If we had stored uid from Firebase Auth as our primary user key, we should maintain a mapping in the user table so existing IDs still match.
    • For any references to Firebase RTDB keys, we can store them as strings in MongoDB’s _id or a dedicated field, ensuring old references remain valid.

3.5 API Contract and Component Rationale

1. NoSQL Database (MongoDB)

Purpose

  • Stores and synchronizes near real-time data such as sports event details, recommended bets, and location-based logs.
  • Provides a high-level interface for other modules to read and write fast-changing or real-time data.

Typical Usage

  • The Bet Management Module references upcoming events and recommended bets here.
  • The Location/Time-Based Event Processor logs location/incidents.
  • The Analytics & Recommendation Engine writes recommended bets and metrics for near real-time display.
  • The Real-Time Event Processor monitors newly inserted or updated events to broadcast them via WebSockets.
  • The mobile app (user) subscribes to updates from the Real-Time Event Processor or can fetch data via the Unified API Layer.

Database Access

  • Accessed directly by Django (or related services) using MongoDB drivers/ODM.
  • No separate REST endpoints; modules interact with MongoDB internally.

2. ACID Database (PostgreSQL)

Purpose

  • Ensures transactional integrity for critical data, including bets, user balances, and minimal references to events.
  • The Bet Management Module and User Management Module perform synchronous CRUD/transactional operations here.
  • The Analytics & Recommendation Engine periodically reads from this database (e.g., user bets, balances).

Typical Usage

  • Bets: creation, updates, status changes, user balance handling.
  • Users: core profile data, account/balance info.
  • Events: minimal references (IDs, timestamps) to maintain bet integrity.

Database Access

  • Accessed via Django ORM calls and transactions; no separate “database API” is published.

3. Sports Data Integration Module

(Background Worker – polls external providers & registers webhooks)

Purpose

  • Serves as an adapter to external sports data providers.
  • Updates MongoDB (detailed event status/odds) and PostgreSQL (minimal event records, if needed) with new or updated event info.
  • Operates on a schedule (e.g., every minute) to poll for upcoming events.
  • Registers webhooks with providers for real-time updates on live events.

API Contract

Inbound (internal or administrative calls)

1) startPolling(providerId: string)
2) stopPolling(providerId: string)
3) registerEventWebhook(eventId: string, callbackUrl: string)
4) onWebhookReceived(payload: any) // Provider calls this endpoint with live updates

Database Access

  • Writes to MongoDB (event details).
  • Updates PostgreSQL if minimal event references or status are required.

4. Sports Data Provider (External)

Purpose

  • Third-party service(s) supplying real-time sports data, odds, and scores.
  • Not under direct control; the Sports Data Integration Module interacts with it.

API Contract (High-Level)

Outbound (our calls to the provider):

1) pollEvents(providerId: string)
2) registerWebhook(eventId: string, callbackUrl: string)

Inbound (provider → our webhook endpoint):

1) POST /webhook/<providerName> // Delivers live updates (scores, odds) to our integration module

5. Location/Time-Based Event Processor

(Real-time Processing Service subscribed to spatiotemporal events)

Purpose

  • Receives user location/time data (via the Unified API Layer) to determine proximity or attendance at sports events.
  • Reads event data from MongoDB (location, start time, etc.).
  • Logs proximity/attendance incidents in MongoDB.
  • Notifies the user via an external Push Service when conditions match.

API Contract

Inbound (from the Unified API Layer or a pub/sub queue):

1) processLocationUpdate(userId: string, locationData: any, timestamp: Date)
   - Checks MongoDB for event details, decides proximity/attendance status.

Outbound (to MongoDB and Push Service):

2) recordProximityIncident(userId: string, eventId: string)
3) recordAttendanceIncident(userId: string, eventId: string)
4) sendNotification(userId: string, notificationData: any)

Database Access

  • Reads event data from MongoDB.
  • Writes incidents (proximity, attendance) back to MongoDB.

6. Real-Time Event Processor

(Real-time Processing Service that pushes new events to users via WebSockets)

Purpose

  • Establishes WebSocket connections with the mobile app (or other frontends) to send newly registered or updated sporting events in real time.
  • Listens to changes in the MongoDB events collection (e.g., via change streams or other triggers).
  • Broadcasts relevant updates (e.g., newly created events) to all subscribed clients.

API Contract

Inbound

  • The Unified API Layer (or a separate endpoint in the Django monolith) upgrades a request to a WebSocket connection, allowing the user (mobile app) to subscribe to real-time event notifications.
  • Internally, the Real-Time Event Processor monitors MongoDB changes to detect new or updated events.
1) subscribeToEvents(userId: string, socketConnection: WebSocket)
   - Called when the user’s client opens a WebSocket to the Real-Time Event Processor.
   - The user may send subscription parameters (e.g., event filters).

Outbound

2) pushNewEvent(eventData: any)
   - Broadcasts a newly created event (or updated event info) to all subscribed WebSocket clients.

Database Access

  • No direct writes to the database in many cases. It primarily listens to MongoDB changes (read operations) and forwards them in real time via WebSockets.
  • May optionally log or track subscriptions in MongoDB, depending on needs.

7. Push Service (External)

Purpose

  • Provides external push notifications to users (e.g., prompting them to attend or bet on an event).
  • We do not implement this in-house.

API Contract (High-Level)

1) sendPushMessage(userToken: string, messagePayload: any)

8. Analytics & Recommendation Engine

(Batch/Stream Processing Service, scheduled nightly or periodically)

Purpose

  • Ingests data from PostgreSQL (bets, user data) and MongoDB (events, incidents).
  • Generates recommended bets, attendance metrics, conversion rates, etc.
  • Writes results (recommended bets, analytics) back into MongoDB for near real-time access.

API Contract

Inbound (e.g., cron job or scheduler):

1) runDailyAnalytics()
   - Main entry point for analytics tasks.

Outbound (to MongoDB):

2) storeRecommendations(userId: string, recommendations: any)
3) storeMetrics(metrics: any)

Database Access

  • Reads from PostgreSQL (ACID data) and MongoDB (events/incidents).
  • Writes new recommended bets or metrics into MongoDB.

9. Bet Management Module (Core Business Logic Service)

Purpose

  • Manages bet-centric operations (listing events, placing bets, retrieving bet history).
  • Called synchronously by the Unified API Layer.
  • Integrates with:
    • PostgreSQL for bets and user balances (transactional).
    • MongoDB for real-time event status or recommended bets.

API Contract

Inbound (from the Unified API Layer):

1) listEvents(filterParams: any) => Promise<any[]>
   - Fetches upcoming events from MongoDB.

2) listRecommendedBets(userId: string, filterParams: any) => Promise<any[]>
   - Reads from MongoDB (recommendedBets collection).

3) placeBet(userId: string, betInfo: any) => Promise<BetConfirmation>
   - Creates a bet (ACID transaction in PostgreSQL).

4) getBetHistory(userId: string) => Promise<any[]>
   - Queries bet records in PostgreSQL.

5) getBetDetails(betId: string) => Promise<any>
   - Retrieves a single bet’s details from PostgreSQL.

6) createOrUpdateEvent(eventInfo: any) => Promise<string>
   - (Optional) For admin tasks to add minimal event data in PostgreSQL + full 
details in MongoDB.

7) getEventDetails(eventId: string) => Promise<any>
   - Retrieves a single event details from PostgreSQL.

Database Access

  • Django ORM for PostgreSQL (bets, users, minimal event data).
  • MongoDB driver for real-time event details or recommended bets.

10. User Management Module (Support Service)

Purpose

  • Handles standard user CRUD (profiles, preferences) aside from authentication.
  • Invoked by the Unified API Layer for user-related actions.
  • Stores user data in PostgreSQL (and in MongoDB if additional real-time user data is required).

API Contract

Inbound (from the Unified API Layer):

1) createUser(userData: any) => Promise<string>
2) getUser(userId: string) => Promise<any>
3) updateUser(userId: string, userData: any) => Promise<void>
4) deleteUser(userId: string) => Promise<void>

Database Access

  • PostgreSQL (main user table via Django ORM).

11. User Authentication Service (External)

Purpose

  • External service for user sign-up, login, and token management.
  • Not implemented internally.

API Contract (High-Level)

1) POST /auth/register 
2) POST /auth/login 
3) verifyToken(token: string) => Promise<AuthUser>

12. Unified API Layer (API Gateway)

Purpose

  • The entry point for all user-facing HTTP/HTTPS calls.
  • Routes requests to Bet Management and User Management modules.
  • Forwards location updates to the Location/Time-Based Event Processor.
  • May also help establish or route WebSocket connections to the Real-Time Event Processor.
  • Delegates token verification to the External Authentication Service.

API Contract

Inbound (from Mobile App / Frontend):

1) POST /users
2) GET /users/{userId}
3) PUT /users/{userId}
4) DELETE /users/{userId}

5) GET /events
6) GET /events/recommended
7) GET /events/{eventId}

8) POST /bets
9) GET /bets
10) GET /bets/{betId}

11) POST /location
   - Sends location/time data to the Location/Time-Based Event Processor.

12) WS /realtime
   - (Optional) Upgrades to a WebSocket for real-time event updates, connecting to the Real-Time Event Processor.

Database Access

  • The API Layer does not directly access databases; it calls internal modules, which perform SQL/NoSQL queries.

13. User (Mobile App)

Purpose

  • Communicates with the Unified API Layer for synchronous requests (HTTP/HTTPS).
  • Maintains real-time/near real-time updates through the Real-Time Event Processor (WebSockets).
  • Receives push notifications from the Push Service.

Key Interactions

  1. Login/Register – Uses the External Auth Service for credential management.
  2. View/Filter Events – Calls GET /events or stays subscribed to the Real-Time Event Processor for new events.
  3. View Recommended Bets – Calls GET /events/recommended or listens for updates in real time if needed.
  4. Place a Bet – Calls POST /bets (transaction handled in PostgreSQL).
  5. View Bet History – Calls GET /bets and GET /bets/{betId}.
  6. Send Location Updates – Calls POST /location to facilitate proximity/attendance checks.
  7. Real-Time Updates – Opens a WebSocket connection (WS /realtime) to receive new event notifications from the Real-Time Event Processor.

Asynchronous / Background Processes

  1. Sports Data Integration Module

    • Polls external sports providers on a schedule; handles webhook callbacks for live events.
    • Updates MongoDB (detailed event data) and PostgreSQL (minimal event records) accordingly.
  2. Location/Time-Based Event Processor

    • Receives location updates from the Unified API.
    • Evaluates proximity/attendance, logs to MongoDB, triggers push notifications.
  3. Real-Time Event Processor

    • Monitors MongoDB for newly registered events or updates.
    • Pushes those changes over WebSockets to subscribed users.
  4. Analytics & Recommendation Engine

    • Scheduled daily ingestion of data from PostgreSQL and MongoDB.
    • Outputs recommended bets and analytics metrics back to MongoDB.

Final Notes

  • This updated contract reflects a Django-based backend (on GCP) using PostgreSQL and MongoDB.
  • The Real-Time Event Processor now appears explicitly, handling WebSocket connections for immediate event notifications.
  • Existing modules (Bet Management, User Management, Analytics) remain intact, but they now interact with MongoDB/PostgreSQL via Django ORM or MongoDB drivers instead of Firebase SDK calls.

3.6 Input/Output Format for API Contract

Key Conventions Used Throughout

  • JSON-based request/response bodies (or message payloads).
  • ISO 8601 timestamps (UTC) for date/time fields (e.g., "2025-01-15T19:20:30Z").
  • Strings for UUIDs or other unique IDs (e.g., "userId": "abc123").
  • Numbers for currency, odds, stakes, etc., with decimal precision as needed.
  • Optional fields are noted as such.
  • Examples are illustrative; field names should match our final code and DB schema.

1. Sports Data Integration Module

(Background worker that polls external sports data providers and handles webhooks)

1.1 startPolling(providerId: string) => void

Purpose

  • Instructs this module to begin polling a particular sports data provider on a scheduled interval.

Input Example

{
  "providerId": "extProvider001"
}

Behavior

  • The module begins periodic REST calls to the provider (e.g., pollEvents) to fetch upcoming events.

Output

  • No direct output (a success/failure status might be returned internally).

1.2 stopPolling(providerId: string) => void

Purpose

  • Stops periodic polling for a given provider.

Input Example

{
  "providerId": "extProvider001"
}

Output

  • No direct output.

1.3 registerEventWebhook(eventId: string, callbackUrl: string) => void

Purpose

  • Tells a provider to send live updates for a specific event to our callbackUrl.

Input Example

{
  "eventId": "evt123",
  "callbackUrl": "https://api.myapp.com/webhook/providerABC"
}

Output

  • No direct output.

1.4 onWebhookReceived(payload: any) => void

Purpose

  • Inbound HTTP endpoint that external providers call to deliver live updates (scores, odds, etc.).

Input Example (Provider → Our System)

{
  "providerEventId": "AAA111",
  "timestamp": "2025-03-19T20:15:00Z",
  "updateType": "scoreUpdate",
  "details": {
    "score": "2-1",
    "status": "live",
    "odds": 1.75
  }
}

Behavior

  • The module processes the incoming data and updates MongoDB (detailed event info) and/or PostgreSQL (minimal event reference), as needed.
  • Responds with an HTTP 2xx to the provider if successful.

2. Location/Time-Based Event Processor

(Real-time processing service to handle geofencing logic)

2.1 processLocationUpdate(userId: string, locationData: any, timestamp: string) => void

Purpose

  • Receives a user’s current location and time, checks if they are near or attending a sports event, and logs incidents if so.

Input Example

{
  "userId": "userABC",
  "locationData": {
    "lat": 40.7128,
    "lng": -74.0060
  },
  "timestamp": "2025-03-19T18:00:00Z"
}

Behavior

  • Fetches relevant event info from MongoDB (looking at event location, start time).
  • Decides if the user is near or actually attending.
  • If relevant, calls recordProximityIncident or recordAttendanceIncident, then sendNotification.

Output

  • No direct response (aside from success/failure).

2.2 recordProximityIncident(userId: string, eventId: string) => void

Purpose

  • Logs a “proximity” occurrence for a user-event pair.

Input Example

{
  "userId": "userABC",
  "eventId": "evt001"
}

Behavior

  • Inserts a document into MongoDB (e.g., incidents collection) with type = proximity.
  • No direct return value.

2.3 recordAttendanceIncident(userId: string, eventId: string) => void

Purpose

  • Logs an “attendance” occurrence for a user-event pair.

Input Example

{
  "userId": "userABC",
  "eventId": "evt001"
}

Behavior

  • Similar to proximity, but logs type = attendance in MongoDB.

2.4 sendNotification(userId: string, notificationData: any) => void

Purpose

  • Invokes an external push service to deliver a notification to the user.

Input Example

{
  "userId": "userABC",
  "notificationData": {
    "title": "Near Upcoming Event!",
    "body": "we're within 100m of the stadium. Check it out!",
    "eventId": "evt001"
  }
}

Behavior

  • Calls the Push Service with the user’s device token and this message.

3. Real-Time Event Processor

(Pushes newly registered or updated events to connected users via WebSockets)

3.1 WebSocket Subscription

Endpoint: WS /realtime (or similar)

  • The client (mobile app) initiates a WebSocket connection to subscribe to real-time event notifications.

Inbound (Client → Server over WebSocket)

SUBSCRIBE {"userId": "userABC", "filters": {"sport": "basketball"}}
  • The user may send a subscription message specifying which events they want to listen for.

Outbound (Server → Client over WebSocket)

{
  "type": "eventCreated",
  "eventData": {
    "eventId": "evt002",
    "acidEventId": "sql-evt002",
    "name": "Team X vs Team Y",
    "sport": "basketball",
    "startTime": "2025-03-19T21:00:00Z",
    "status": "upcoming",
    "providerId": "providerXYZ",
    "team1:" "Los Andes",
    "team2:" "La javeriana"
  }
}
  • The Real-Time Event Processor watches MongoDB (e.g., via change streams) and pushes newly created or updated events to all subscribed clients.

4. Push Service (External)

4.1 sendPushMessage(userToken: string, messagePayload: any) => void

Purpose

  • External push provider (e.g., FCM, OneSignal). We call it with the device token and the message.

Input Example

{
  "userToken": "fcmtoken_abcdef123456",
  "messagePayload": {
    "title": "Near Upcoming Event!",
    "body": "Come watch the game!",
    "eventId": "evt001"
  }
}

Output

  • No direct output from the push service to our system (aside from a success/failure).

5. Analytics & Recommendation Engine

(Batch/stream processing service running periodically)

5.1 runDailyAnalytics() => void

Purpose

  • Main entry point for daily or scheduled analytics tasks.

Behavior

  1. Reads user and bet data from PostgreSQL.
  2. Reads event and incident data from MongoDB.
  3. Computes recommended bets, attendance metrics, or other KPIs.
  4. Calls storeRecommendations and storeMetrics (below).

No direct input; triggered by a scheduler (cron).


5.2 storeRecommendations(userId: string, recommendations: any[]) => void

Purpose

  • Writes recommended bets to MongoDB so they appear in real time or near real time for the user.

Input Example

{
  "userId": "userABC",
  "recommendations": [
    {
      "recommendationId": "r001",
      "eventId": "evt123",
      "betType": "WIN",
      "description": "High chance for Team A based on recent performance",
      "createdAt": "2025-03-20T03:00:00Z"
    },
    {
      "recommendationId": "r002",
      "eventId": "evt456",
      "betType": "OVER_UNDER",
      "description": "Likely a low-scoring match...",
      "createdAt": "2025-03-20T03:00:00Z"
    }
  ]
}

Behavior

  • For each recommendation, inserts/updates a document in MongoDB’s recommendedBets collection keyed by userId.

5.3 storeMetrics(metrics: any[]) => void

Purpose

  • Writes aggregated analytics (e.g., conversion rates, total attendance) to MongoDB.

Input Example

{
  "metrics": [
    {
      "metricId": "m001",
      "type": "conversionRate",
      "eventId": "evt123",
      "value": 0.45,
      "timestamp": "2025-03-20T03:00:00Z"
    },
    {
      "metricId": "m002",
      "type": "attendanceCount",
      "eventId": "evt456",
      "value": 157,
      "timestamp": "2025-03-20T03:00:00Z"
    }
  ]
}

Behavior

  • Inserts these metrics into MongoDB’s analytics collection.

6. Bet Management Module

(Core business logic for bets and events)

6.1 listEvents(filterParams: any) => Promise<any[]>

Purpose

  • Returns upcoming events, optionally filtered (by sport, date range, etc.).

Input Example

{
  "filterParams": {
    "sport": "soccer",
    "startDate": "2025-03-19T00:00:00Z",
    "endDate": "2025-03-20T00:00:00Z"
  }
}

Output Example

{
  "events": [
    {
      "eventId": "evt001",
      "acidEventId": "sql-evt001",
      "name": "Team A vs Team B",
      "sport": "soccer",
      "location": {"lat": 40.7128, "lng": -74.0060},
      "startTime": "2025-03-19T19:00:00Z",
      "status": "upcoming",
      "providerId": "extProvider001",
      "team1:" "Los Andes",
      "team2:" "La javeriana"
    },
    ...
  ]
}

Behavior

  • Reads MongoDB for detailed event data; may also reference PostgreSQL if minimal event data is needed.

6.2 listRecommendedBets(userId: string, filterParams: any) => Promise<any[]>

Purpose

  • Retrieves recommended bets for a given user, possibly with optional filters.

Input Example

{
  "userId": "userABC",
  "filterParams": {
    "sport": "soccer"
  }
}

Output Example

{
  "recommendedBets": [
    {
      "recommendationId": "r001",
      "eventId": "evt001",
      "betType": "WIN",
      "description": "Team A is likely to win...",
      "createdAt": "2025-03-20T03:00:00Z"
    },
    ...
  ]
}

Behavior

  • Reads from the recommendedBets collection in MongoDB for that user.

6.3 placeBet(userId: string, betInfo: any) => Promise<BetConfirmation>

Purpose

  • Creates a new bet transaction in PostgreSQL, adjusting user balance if needed.

Input Example

{
  "userId": "userABC",
  "betInfo": {
    "eventId": "sql-evt001",
    "stake": 50.0,
    "odds": 1.85
  }
}

Output Example

{
  "betId": "bet555",
  "status": "placed",
  "timestamp": "2025-03-19T19:05:00Z"
}

6.4 getBetHistory(userId: string) => Promise<any[]>

Purpose

  • Returns a list of bets placed by the user, from PostgreSQL.

Input Example

{
  "userId": "userABC"
}

Output Example

{
  "bets": [
    {
      "betId": "bet555",
      "eventId": "sql-evt001",
      "stake": 50.0,
      "odds": 1.85,
      "status": "placed",
      "created_at": "2025-03-19T19:05:00Z",
      "updated_at": "2025-03-19T19:05:00Z"
    },
    ...
  ]
}

6.5 getBetDetails(betId: string) => Promise<any>

Purpose

  • Retrieves the detailed info for a single bet (from PostgreSQL).

Input Example

{
  "betId": "bet555"
}

Output Example

{
  "bet": {
    "betId": "bet555",
    "userId": "userABC",
    "eventId": "sql-evt001",
    "stake": 50.0,
    "odds": 1.85,
    "status": "placed",
    "created_at": "2025-03-19T19:05:00Z",
    "updated_at": "2025-03-19T19:05:00Z"
  }
}

6.6 createOrUpdateEvent(eventInfo: any) => Promise<string>

Purpose

  • Creates or updates an event record in both PostgreSQL (for minimal ACID references) and MongoDB (for full details).

Input Example

{
  "eventInfo": {
    "acidEventId": "sql-evt001",     // optional if updating
    "eventId": "evt001",            // optional if new
    "name": "Team A vs Team B",
    "sport": "soccer",
    "location": {"lat": 40.7128, "lng": -74.0060},
    "startTime": "2025-03-19T19:00:00Z",
    "status": "upcoming",
    "providerId": "extProvider001",
    "team1:" "Los Andes",
    "team2:" "La javeriana"
  }
}

Output Example

{
  "eventId": "evt001"
}
  • Returns the final MongoDB _id (or an equivalent string) if newly created, or the existing ID if updated.

7. User Management Module

(Handles basic user CRUD in PostgreSQL)

7.1 createUser(userData: any) => Promise<string>

Purpose

  • Inserts a new user into PostgreSQL.

Input Example

{
  "userData": {
    "email": "[email protected]",
    "phone": "555-1234",
    "name": "John Doe",
    "balance": 100.0
  }
}

Output Example

{
  "userId": "userABC"
}

7.2 getUser(userId: string) => Promise<any>

Purpose

  • Retrieves a user record from PostgreSQL by ID.

Input Example

{
  "userId": "userABC"
}

Output Example

{
  "user": {
    "user_id": "userABC",
    "email": "[email protected]",
    "phone": "555-1234",
    "name": "John Doe",
    "balance": 100.0,
    "created_at": "2025-03-19T18:55:00Z",
    "updated_at": "2025-03-19T18:55:00Z"
  }
}

7.3 updateUser(userId: string, userData: any) => Promise<void>

Purpose

  • Updates an existing user in PostgreSQL.

Input Example

{
  "userId": "userABC",
  "userData": {
    "phone": "555-9999",
    "name": "Johnny D"
  }
}

Output

  • No direct body (just success/failure).

7.4 deleteUser(userId: string) => Promise<void>

Purpose

  • Removes the user record from PostgreSQL (and possibly from MongoDB if relevant).

Input Example

{
  "userId": "userABC"
}

Output

  • No direct body (just success/failure).

8. User Authentication Service (External)

8.1 POST /auth/register

Purpose

  • Registers a new user credential in an external auth provider.

Input Example

{
  "email": "[email protected]",
  "password": "secretPass"
}

Output Example

{
  "authUserId": "external-uid-123",
  "idToken": "jwt-token-here"
}

(Exact fields depend on the external service.)


8.2 POST /auth/login

Purpose

  • Authenticates user credentials.

Input Example

{
  "email": "[email protected]",
  "password": "secretPass"
}

Output Example

{
  "authUserId": "external-uid-123",
  "idToken": "jwt-token-here"
}

8.3 verifyToken(token: string) => Promise<AuthUser>

Purpose

  • Verifies an externally issued token (JWT or similar).

Input Example

{
  "token": "jwt-token-here"
}

Output Example

{
  "authUserId": "external-uid-123",
  "email": "[email protected]"
  // Additional fields depending on the auth service
}

9. Unified API Layer (API Gateway)

(High-level HTTP endpoints exposed to the mobile app.)

9.1 POST /users

Request Body (example):

{
  "email": "[email protected]",
  "phone": "555-1234",
  "name": "John Doe",
  "balance": 100.0
}

Response Body (example):

{
  "userId": "userABC"
}

9.2 GET /users/{userId}

Response Body (example):

{
  "user": {
    "user_id": "userABC",
    "email": "[email protected]",
    "phone": "555-1234",
    "name": "John Doe",
    "balance": 100.0,
    "created_at": "2025-03-19T18:55:00Z",
    "updated_at": "2025-03-19T18:55:00Z"
  }
}

9.3 PUT /users/{userId}

Request Body (example):

{
  "phone": "555-9999",
  "name": "Johnny D"
}

Response:

  • No JSON body (just HTTP success/failure).

9.4 DELETE /users/{userId}

  • No request body.
  • No response body (HTTP success/failure).

9.5 GET /events

  • Query Parameters for filtering (e.g., sport, startDate, etc.).
  • Response Body (example):
    {
      "events": [
        {
          "eventId": "evt001",
          "acidEventId": "sql-evt001",
          "name": "Team A vs Team B",
          "sport": "soccer",
          "location": {"lat": 40.7128, "lng": -74.0060},
          "startTime": "2025-03-19T19:00:00Z",
          "status": "upcoming",
          "providerId": "extProvider001",
          "team1": "Los Andes",
          "team2": "La javeriana"
        },
        ...
      ]
    }

9.6 GET /events/recommended

  • Response Body (example):
    {
      "recommendedBets": [
        {
          "recommendationId": "r001",
          "eventId": "evt001",
          "betType": "WIN",
          "description": "Team A has a strong advantage...",
          "createdAt": "2025-03-20T03:00:00Z"
        },
        ...
      ]
    }

9.7 POST /bets

Request Body (example):

{
  "eventId": "sql-evt001",
  "stake": 50.0,
  "odds": 1.85
}

Response Body (example):

{
  "betId": "bet555",
  "status": "placed",
  "timestamp": "2025-03-19T19:05:00Z"
}

9.8 GET /bets

Response Body (example):

{
  "bets": [
    {
      "betId": "bet555",
      "eventId": "sql-evt001",
      "stake": 50.0,
      "odds": 1.85,
      "status": "placed",
      "created_at": "2025-03-19T19:05:00Z",
      "updated_at": "2025-03-19T19:05:00Z"
    },
    ...
  ]
}

9.9 GET /bets/{betId}

Response Body (example):

{
  "bet": {
    "betId": "bet555",
    "userId": "userABC",
    "eventId": "sql-evt001",
    "stake": 50.0,
    "odds": 1.85,
    "status": "placed",
    "created_at": "2025-03-19T19:05:00Z",
    "updated_at": "2025-03-19T19:05:00Z"
  }
}

9.10 POST /location

Request Body (example):

{
  "lat": 40.7128,
  "lng": -74.0060,
  "timestamp": "2025-03-19T18:00:00Z"
}

Response

  • No body (just HTTP success/failure).
  • Internally, the API Gateway calls processLocationUpdate(userId, { lat, lng }, timestamp) in the Location/Time-Based Event Processor.

10. User (Mobile App)

  • Calls the Unified API (HTTP endpoints above) with JSON request/response.
  • Connects to the Real-Time Event Processor via WebSockets to receive new event notifications.
  • Receives push notifications from the Push Service on the device.

Typical Interactions

  1. Authentication – The user logs in via the External Auth Service (obtain a token).
  2. List EventsGET /events or subscribe to new event notifications over WebSocket.
  3. Recommended BetsGET /events/recommended.
  4. Place BetPOST /bets.
  5. Bet HistoryGET /bets or GET /bets/{betId}.
  6. Location UpdatesPOST /location with lat/lng/timestamp.
  7. Receiving Notifications – Real-time push messages from the Push Service or real-time event messages over WebSockets from the Real-Time Event Processor.

Final Notes

  1. Data Flows

    • PostgreSQL holds user and bet data for ACID transactions.
    • MongoDB stores detailed event info, recommended bets, incidents, and analytics.
    • No direct “API” calls to these databases are exposed; each module uses internal drivers/ORM in Django or background workers to read/write data.
  2. Timestamp Consistency

    • All timestamps use ISO 8601 strings in requests and responses. The databases may store them in timestamp fields.
  3. Field Names

    • The examples show potential structures. The actual field names must match our final models (e.g., created_at, startTime).
  4. Authentication & Authorization

    • Requests to the Unified API typically include a token from the External Auth Service. The gateway verifies the token before calling internal modules.
  5. Error Handling

    • Each endpoint should return appropriate HTTP status codes (4xx for client errors, 5xx for server errors) along with a JSON body if needed (e.g., an error field).

With this structure, our Input/Output formats align with the new Django monolith (PostgreSQL + MongoDB) architecture and the additional Real-Time Event Processor—while retaining the same functionality previously described for Firebase-based designs.


3.7 Mobile App Diagram

mobile_app In this Flutter application, the architecture follows an enhanced MVVM (Model–View–ViewModel) pattern that integrates multiple modules to ensure separation of concerns and maintainability. The View layer is composed of UI components (e.g., login_screen.dart, home_screen.dart, and settings_screen.dart) that render the interface and capture user interactions. These components are supported by dedicated ViewModels (such as LoginViewModel, HomeViewModel, and SettingsViewModel), which handle presentation logic, state management, and mediate between the UI and the underlying data. The Model layer encapsulates the core business data and logic through entities like the User Model, Auth Model, and Settings Model. To manage data operations efficiently, a Repository layer (with modules like AuthRepository, DataRepository, and SettingsRepository) acts as a mediator, abstracting the complexities of data fetching and updating. Finally, the Service layer, which includes components like API Service and Database Service, provides low-level functionality for network communication and database interactions. This modular design not only improves testability and scalability but also allows each component to evolve independently without affecting the overall system.


4. List of Implemented Features (IF)


  1. Location-Based Event Detection (Uses a Phone Sensor)

    • What: Continuously gather real-time GPS coordinates from the mobile device.
    • How:
      • Implement background location tracking with appropriate device permissions (e.g., iOS Core Location or Android Location Services).
      • Set up geofences around known university sports venues.
    • Why:
      • Needed to detect if the user is at or near a sports venue during an event.
    • Requirements Addressed: (a) Uses phone sensor (GPS), (c) Context awareness, (b) & (f) also feed into Type 2 questions and triggers.
  2. Real-Time Betting Prompt Trigger (Answers Type 2 Questions)

    • What: Display a pop-up betting prompt when the user is detected at an active sports game (or is near one).
    • How:
      • Upon receiving a “user isAtGame = true” signal from the backend, the mobile app pushes a betting prompt to the foreground.
      • Include quick-bet options and real-time reporting.
    • Why:
      • Directly addresses Type 2 questions by providing “real-time betting opportunities tailored to the user’s situation.”
    • Requirements Addressed: (b) Answers Type 2 questions.
  3. Context-Aware Notifications (Context Awareness)

    • What: Automatically send alerts about ongoing or upcoming sports events if the user enters a defined proximity threshold (e.g., within 500 meters).
    • How:
      • Monitor geospatial data against event locations.
      • When proximity is detected, trigger a push notification with event details.
    • Why:
      • Ensures the user receives relevant information at the right time and place.
    • Requirements Addressed: (c) Context-aware functionality, (b) also aligns with providing timely info.
  4. Smart Bet Recommendations (Smart Feature)

    • What: Analyze a user’s betting history to identify repeated bets on the same team and generate personalized recommendations or promotions.
    • How:
      • On the backend, aggregate recent betting transactions to compute a “loyalty index.”
      • If loyalty surpasses a set threshold, push targeted bet suggestions to the user’s app.
    • Why:
      • Delivers a personalized, “smart” feature that increases engagement.
    • Requirements Addressed: (d) Smart feature.
  5. User Authentication Module (Allows User Authentication)

    • What: Implement a secure login and session management system.
    • How:
      • Support standard custom email-password login.
      • Maintain session tokens and encrypt sensitive data.
    • Why:
      • Ensures only authorized users can place bets and receive personalized prompts.
    • Requirements Addressed: (e) User authentication.
  6. External Sports Calendar Integration (Uses External Services)

    • What: Fetch event schedules from a sports calendar API to check if a game is in progress.
    • How:
      • Query an external sports event service (e.g., ESPN API or a university sports calendar).
      • Match event times and locations with user GPS data in real-time.
    • Why:
      • Essential to determine if a game is active and to schedule relevant notifications and prompts.
    • Requirements Addressed: (f) Uses external service distinct from authentication.

    Thanks for the details! I will now research and list additional features and screens that are essential to complement the existing functionalities for your Android-focused sports betting MVP. These will focus on minimal yet necessary components to ensure a streamlined experience, covering features like UI elements, event tracking, user engagement, and real-time betting mechanics.

  7. Sports Event r

    • What: A user interface for browsing upcoming and live sports events. This is typically the home screen or main lobby of the app where users can see a list of matches/games available to bet on. Events can be organized by sport or date, and each listing shows basic details (teams/players, start time) and available odds for simple bets (e.g. win/lose).
    • How: The app pulls schedule data from the integrated sports calendar (existing Feature 6) and displays it in a scrollable list or card format. For each event, the relevant odds are fetched from a basic odds source (could be a static feed or simple odds generator for MVP). Users can tap an event to see more details or directly select a bet outcome. The UI will follow Android Material Design guidelines for clarity – e.g. using tabs or filters to quickly find sports or leagues. This screen remains streamlined, showing only essential info and a “Bet” button for each outcome to maintain a clean look. (For example, if location-based detection (Feature 1) finds a user near a stadium, the app could highlight that local game at the top of the list.)
    • Why: This feature is the cornerstone of user interaction – without it, users have no easy way to find and choose what to bet on. Industry best-practices note that a sports betting app must let users see the schedule of matches and available bets, and place wagers in just a few clicks (Sports Betting App Development: Comprehensive Guide | Cogniteq). Providing a simple, intuitive browsing experience ensures the app is functional even when users aren’t receiving recommendations or notifications. It empowers users to explore betting options on their own, which is essential for engagement and a user-friendly MVP.
  8. Bet Selection & Bet Slip Confirmation

    • What: The workflow for selecting a bet outcome and confirming the wager through a “bet slip.” The bet slip is a common betting app interface that collects the user’s chosen bet(s), allows them to enter a stake (amount of points or tokens to wager), and then confirm the bet. This feature covers the screens and logic from the moment a user picks a specific outcome (e.g., Team A to win) to the final confirmation of placing that bet.
    • How: When a user taps on an odd or outcome in the event list, the app adds that pick to a bet slip UI – usually a slide-up panel or separate screen showing the selected bet. The bet slip displays details like the chosen event, outcome, the odds, and a field for the user to input their stake (since no real money is involved in the MVP, this could be virtual credits or just for record). The user can review this information, then hit a “Place Bet” (or “Confirm”) button. Upon confirmation, the app’s backend (or local database) records the bet with all relevant info (user ID, event, pick, odds, time). A confirmation message or dialog then notifies the user that their bet is placed. The UI/UX is kept minimal – for example, a single bet slip at a time (no complex multi-bet parlays for MVP) to avoid overwhelming the user. This feature leverages Android’s native dialogs or new activities for smooth transitions and uses simple form validation (e.g., stake must be a positive number).
    • Why: Placing a bet is the core action in a sports betting app – it’s what all other prompts and recommendations ultimately lead to. A dedicated bet slip ensures the user understands what they are betting on and the potential outcome before finalizing, which improves clarity and reduces mistakes. This confirmation step is crucial for user confidence, especially in a real betting scenario. Even though the MVP won’t handle real money, mimicking this bet slip flow prepares the app for future enhancements. It also keeps the UI streamlined by not immediately cluttering the main screen with input fields – instead, it isolates the betting interaction in a focused overlay, aligning with a clean Android UX.

12. Unified Navigation Design (Nav Bar / Drawer / Tabs)

  • What:
    A structured navigation layout that allows users to quickly switch between the core sections of the app—e.g., Home (Sports Events), Live Games, Bet History, and Profile/Settings. This ensures a consistent and intuitive user flow across all the features listed so far.

  • How:

    1. Navigation Pattern:

      • Bottom Navigation Bar: Common in Android apps for up to 3–5 primary sections. It typically includes icons (and optionally text labels) for quick access.
      • Navigation Drawer: If more space is required for secondary links or if a simpler main screen is desired, an expandable drawer can be used.

      For an MVP, a Bottom Navigation Bar with 3–4 main items is often more straightforward and modern:

      • “Home/Events” (Default/Primary): Shows the Sports Event & Odds Browser (Feature 7).
      • “Live”: Direct link to any live game list or real-time betting (Feature 9).
      • “History”: Direct link to Bet History & Outcome Tracking (Feature 10).
      • “Profile” (or a similar icon): Takes users to the User Profile & Preferences (Feature 11).
    2. Navigation Implementation:

      • Use Android’s Jetpack Navigation Component or a standard Fragment-based approach, with each feature represented by a fragment or activity.
      • Set up consistent App Bars/Toolbars for each screen, showing relevant titles (“Events,” “Live Games,” “History,” “Profile”), with a back button when necessary.
      • For cross-feature transitions (e.g., tapping an event on the “Home” screen navigates to a detail screen for Bet Selection & Bet Slip Confirmation, Feature 8), ensure that the user can easily return to the main screen via the nav bar or the top-left “Back” arrow.
    3. Contextual Navigation:

      • If a real-time prompt (Feature 2) or context-aware notification (Feature 3) takes the user to a specific bet page, the user should still be able to access the bottom nav to switch sections.
      • Highlight the active section of the navigation bar using a colored icon or text label to let the user know where they are in the app.
  • Why:

    • User-Friendliness: Having a unified nav structure is crucial for discoverability and consistency across all features. Users expect to find primary app sections in a persistent navigation bar or a clearly accessible drawer.
    • Efficiency: Quick switching between the main features—Events, Live, History, Profile—improves overall usability, especially for an app that depends on timely interaction and real-time updates.
    • Scalability: As more features are added in future iterations (e.g., payments, advanced stats), a well-designed navigation system allows easy expansion without confusing the user.

5. Ethics Component

⚠️ **GitHub.com Fallback** ⚠️