Skip to content
alexandrebeatoPublic

About

Palpitero FC lets Brazilian football fans predict match results, compete in rankings, and win prizes with no betting risks.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Palpitero FC

Palpitero FC is an app designed for Brazilians who love football and enjoy predicting match results without the risks associated with betting. The app offers a fun and competitive experience, where users can score points based on the accuracy of their predictions and compete in global rankings or personalized groups with friends.

Logo

Architecture

Overview

Palpitero is a full-stack, multi-platform sports prediction application with a layered architecture spanning mobile (React Native/Expo), web (Vue.js), and server-side (.NET) components. The system follows a Clean Architecture / Layered Architecture pattern with clear separation of concerns across domain logic, application services, and infrastructure.

Core Stack:

  • Backend API: ASP.NET Core 8 (C#) with PostgreSQL (relational) + MongoDB (NoSQL)
  • Mobile Client: React Native (Expo) with TypeScript
  • Web Client: Vue.js 3 with JavaScript
  • Background Jobs: Node.js with TypeScript (Scheduled via cron)
  • Containerization: Docker Compose (dev, jobs, infrastructure, production configurations)
  • External Integrations: API-Football (match data), Twilio (SMS), AWS S3 (storage), Expo (push notifications)

Components & Responsibilities

Component Tech Responsibility Evidence
API Server ASP.NET Core 8, PostgreSQL, MongoDB Core business logic, predictions, rankings, user management server/api/src/API/
Mobile App React Native (Expo 53), TypeScript User predictions, live match feed, group management, rankings client/app/
Web Dashboard Vue.js 3, Axios Administrative dashboard, user analytics (planned) client/web/
Background Jobs Node.js, TypeScript, node-cron Match synchronization, prediction scoring, prize calculation server/bot/
Data Layer PostgreSQL + MongoDB Persistent storage (transactions) + NoSQL documents docker-compose.dev.yml, server/api/src/Infra/Data/
Authentication JWT Bearer Tokens User identity and authorization across all clients server/api/src/API/Configurations/
Notifications Expo Push Notifications, Twilio Real-time updates for predictions, match status, prizes server/api/src/Infra/Services/NotificationService.cs

Folder Structure & Responsibilities

Backend (server/api/)

server/api/src/
├── API/                        # Web API entry point
│   ├── Controllers/            # REST endpoints (Predictions, Matches, Users, etc.)
│   ├── Configurations/         # DI, Authentication, CORS, Localization setup
│   ├── Middlewares/            # Request/response interceptors
│   ├── Localization/           # Multi-language JSON files (pt-BR, en, es, fr, de, it)
│   ├── Attributes/             # Custom validation attributes
│   └── Program.cs              # ASP.NET Core configuration entry point
│
├── Application/                # Application services & use-case orchestration
│   ├── Services/               # Business logic (PredictionService, UserService, etc.)
│   ├── Interfaces/             # Service contracts
│   ├── ViewModels/             # DTO contracts for requests/responses
│   └── Mapping/                # AutoMapper profiles (Domain ↔ ViewModel)
│
├── Domain/                     # Domain entities & business rules (per aggregate)
│   ├── Predictions/            # Prediction entity, repository, validations
│   ├── Matches/                # Match entity, repository, business logic
│   ├── Users/                  # User entity, repository
│   ├── Leagues/                # League configuration & filtering
│   ├── Groups/                 # Group creation & membership
│   ├── Rankings/               # Custom ranking definitions
│   ├── Prizes/                 # Prize management & eligibility
│   ├── Minigames/              # Quiz & logo minigames
│   └── [...]                   # Other aggregates
│
├── Core.Domain/                # Cross-cutting domain concerns
│   ├── Entities/               # Base entity classes
│   ├── Interfaces/             # IMediatorHandler, IUser, ITranslator
│   ├── Notifications/          # Domain notification pattern (error collection)
│   ├── Events/                 # Domain events (if any)
│   ├── Auth/                   # JWT, authentication contracts
│   └── Utils/                  # PasswordEncryption, DateTimeUtils
│
└── Infra/                      # Infrastructure & external services
    ├── Data/                   # PostgreSQL DbContext, repositories, EF migrations
    │   ├── DataContext.cs      # Entity Framework DbSet configuration
    │   ├── *Repository.cs      # SQL-based repositories for each aggregate
    │   └── Mappings/           # EF entity mappings (fluent configuration)
    ├── Services/               # External service implementations
    │   ├── TwilioService       # SMS integration
    │   ├── StorageService      # AWS S3 file upload
    │   ├── MailService         # Email (SMTP)
    │   ├── NotificationService # Expo push notifications
    │   └── Translator          # Localization provider
    └── CrossCutting/           # Password encryption, logging

See: Palpitero.sln for project references.

Mobile Client (client/app/)

client/app/
├── app/                        # Expo Router file-based routing
│   ├── (auth)/                 # Auth routes (login, signup, verify email)
│   ├── (tabs)/                 # Tabbed home layout (feed, groups, predictions, profile)
│   ├── groups/                 # Group management screens
│   ├── minigames/              # Quiz and logo prediction minigames
│   ├── profiles/               # User profile & statistics
│   ├── _layout.tsx             # Root layout, auth initialization, token/user loading
│   └── [...routes]             # Feature screens
│
├── components/                 # Reusable UI components (50+ components)
│   ├── MatchCard.tsx           # Individual match prediction card
│   ├── PredictionCard.tsx      # User prediction display
│   ├── RankingCard.tsx         # User ranking in groups/leagues
│   ├── LeaguesPicker.tsx       # Multi-select league filter
│   ├── CustomButton.tsx        # Themed button wrapper
│   ├── CountdownTimer.tsx      # Match countdown display
│   └── [...]                   # Other UI components
│
├── repository/                 # HTTP data access layer (Repository pattern)
│   ├── HttpRepository.ts       # Base class with axios instance & auth headers
│   ├── user.repository.ts      # User sign-in/up, profile endpoints
│   ├── prediction.repository.ts # Prediction CRUD operations
│   ├── match.repository.ts     # Match feed retrieval
│   ├── group.repository.ts     # Group management
│   └── [...]                   # Other repositories
│
├── services/                   # Business logic & utilities
│   ├── auth.service.ts         # JWT token storage, user state singleton
│   ├── storage.service.ts      # AsyncStorage wrapper for local state
│   └── [...]                   # Other services
│
├── models/                     # TypeScript interfaces for API responses
│   ├── predictions/            # Prediction, SetScore DTOs
│   ├── matches/                # Match, MatchCard models
│   ├── users/                  # User, SignIn, SignUp models
│   ├── pagination.model.ts     # Pagination wrapper
│   └── [...]                   # Other domain models
│
├── utils/                      # Helper functions (date, localization, formatting)
├── types/                      # Global TypeScript types
├── constants/                  # App-wide constants, context
├── assets/                     # Icons, images, locale JSON files (i18n)
├── hooks/                      # Custom React hooks (push notifications)
├── globalstyles.ts             # Theming, color palette
├── app.json                    # Expo app configuration
├── eas.json                    # Expo Application Services (iOS/Android builds)
├── package.json                # Dependencies (Expo, React Native, i18n, etc.)
└── tsconfig.json               # TypeScript configuration

See: client/app/app.json, client/app/package.json

Web Client (client/web/)

client/web/
├── src/
│   ├── components/             # Reusable Vue components
│   ├── views/                  # Page-level components
│   ├── router/                 # Vue Router configuration
│   ├── services/               # API/business logic
│   └── App.vue                 # Root component
├── public/                     # Static assets
├── package.json                # Vue 3, Axios, Router
└── vue.config.js               # Webpack configuration

Background Jobs (server/bot/)

server/bot/
├── src/
│   ├── jobs/                   # Scheduled job implementations
│   │   ├── future-matches.job.ts       # Fetch next 24h matches → sync DB
│   │   ├── past-matches.job.ts         # Verify match results, update predictions
│   │   ├── upcoming-matches.job.ts     # Notify users of upcoming matches
│   │   └── prizes.job.ts               # Calculate daily/monthly prizes
│   ├── services/               # External API clients
│   │   ├── api-football.service.ts     # API-Football SDK integration
│   │   └── notification.service.ts     # Expo & Twilio notifications
│   ├── repository/             # Direct DB access (pg client)
│   │   └── *Repository.ts      # PostgreSQL queries via raw SQL/Dapper
│   ├── entities/               # TypeScript DTOs for API responses
│   ├── models/                 # Data transformation models
│   ├── mapper/                 # Entity ↔ Model mappings
│   ├── utils/                  # Timestamp, logging utilities
│   ├── logger.ts               # Colored console output
│   └── main.ts                 # Cron scheduler entry point
├── package.json                # Dependencies (amqplib, pg, node-cron, etc.)
└── tsconfig.json               # TypeScript configuration

See: server/bot/src/main.ts

Key Patterns

Pattern Where Used Evidence
Clean Architecture API (Domain → Application → Infra → API layers) Palpitero.sln project structure
Repository Pattern API data access + Mobile HTTP server/api/src/Infra/Data/, client/app/repository/
Dependency Injection API (Autofac via .NET DI) server/api/src/API/Configurations/DependencyInjectionConfiguration.cs
MediatR / Domain Events API notifications & error handling Core.Domain/Notifications/, DomainNotificationHandler
AutoMapper API ViewModel mapping server/api/src/Application/Mapping/
Entity Framework API database abstraction server/api/src/Infra/Data/DataContext.cs
Fluent Validation API input validation Core.Domain/Validations/, Domain/*/Validations/
Service Layer API business orchestration server/api/src/Application/Services/
Factory Pattern Domain entity creation server/api/src/Domain/Predictions/Prediction.cs (likely Prediction.Factory.Create())
Singleton Pattern Mobile client auth state client/app/services/auth.service.ts AuthService.getInstance()
Observer / MediatR Pattern API domain notifications server/api/src/Core.Domain/Notifications/DomainNotificationHandler.cs
Template Method Base repository & controller server/api/src/Infra/Data/SqlRepository.cs, server/api/src/API/Controllers/BaseController.cs
Strategy Pattern Authentication (JWT, Google, Apple) client/app/repository/user.repository.ts sign-in methods
Adapter Pattern External service wrappers server/api/src/Infra/Services/TwilioService.cs, server/api/src/Infra/Services/StorageService.cs

Integration Patterns

Database Layer

Authentication & Authorization

  • JWT Bearer Tokens:

    • Issued on sign-in/sign-up
    • Mobile client stores token in AsyncStorage (persistent)
    • All API requests include Authorization: Bearer <token> header
    • Server validates via JWT middleware configured in Program.cs
  • Social Sign-In:

External Services

Localization

Data Flow & Processes

Core Prediction Flow

┌─────────────────────────────────────────────────────────┐
│ 1. MATCH SYNC (Background Job - every 24h)              │
├─────────────────────────────────────────────────────────┤
│  server/bot/jobs/future-matches.job.ts                  │
│    ↓                                                     │
│  Fetch from API-Football (configured leagues)           │
│    ↓                                                     │
│  Insert/Update in PostgreSQL (Matches table)            │
│    ↓                                                     │
│  Notify via Expo (new matches available)                │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ 2. USER PREDICTION (Mobile App - real-time)             │
├─────────────────────────────────────────────────────────┤
│  client/app/screens/PredictionScreen                    │
│    ↓                                                     │
│  POST /predictions/set-score (API endpoint)             │
│    ↓                                                     │
│  API/Controllers/PredictionsController.SetScore()       │
│    ↓                                                     │
│  Application/Services/PredictionService.SetScore()      │
│    ├─ Validate via FluentValidation                     │
│    ├─ Check match status (not closed)                   │
│    ├─ Create/Update Prediction entity                   │
│    └─ Persist to PostgreSQL                             │
│       (Infra/Data/PredictionRepository)                 │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ 3. SCORING & RESULTS (Background Job - after matches)   │
├─────────────────────────────────────────────────────────┤
│  server/bot/jobs/past-matches.job.ts (every min)        │
│    ↓                                                     │
│  Check for finished matches from API-Football           │
│    ↓                                                     │
│  Calculate points (3 for exact, 1 for result)           │
│    ↓                                                     │
│  Update Prediction scores in PostgreSQL                 │
│    ↓                                                     │
│  Notify users via Expo (prediction scored)              │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ 4. RANKING UPDATES (Automatic via Entity Framework)    │
├─────────────────────────────────────────────────────────┤
│  RecordRepository aggregates scores                     │
│    ↓                                                     │
│  Global rankings (all leagues)                          │
│  League-specific rankings                               │
│  Custom group rankings                                  │
│    ↓                                                     │
│  GET /records (ranking endpoints) return aggregated    │
└─────────────────────────────────────────────────────────┘

Group & Custom Ranking Flow

┌─────────────────────────────────────────────────────────┐
│ USER CREATES GROUP                                      │
├─────────────────────────────────────────────────────────┤
│ POST /groups (API)                                      │
│   → GroupService.CreateGroup()                          │
│   → GroupRepository.InsertAsync()                       │
│   → Insert Group + Member records (PostgreSQL)          │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ USER CREATES CUSTOM RANKING (within group)             │
├─────────────────────────────────────────────────────────┤
│ POST /custom-rankings (API)                             │
│   → CustomRankingService.CreateCustomRanking()          │
│   → Define league filters + scoring rules               │
│   → CustomRankingRepository.InsertAsync()               │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ GET GROUP RANKING                                       │
├─────────────────────────────────────────────────────────┤
│ GET /records/group/{groupId} (API)                      │
│   → RecordService.GetGroupRanking()                     │
│   → Join Predictions + Matches + CustomRankings        │
│   → Calculate points per league filter                  │
│   → Return ranked members                              │
└─────────────────────────────────────────────────────────┘

Architecture Diagram (Logical)

┌─────────────────────────────────────────────────────────────────────────────┐
│                           CLIENT APPLICATIONS                                │
├──────────────────────────┬─────────────────────────────┬────────────────────┤
│  React Native (Expo)     │     Vue.js Web              │   Node.js Jobs     │
│  - User predictions      │     - Dashboard (planned)   │   - Cron scheduler │
│  - Feeds & rankings      │     - Analytics             │   - Match sync     │
│  - Group management      │                             │   - Score scoring  │
│  - Minigames             │                             │   - Prize calc     │
└──────────────────────────┴─────────────────────────────┴────────────────────┘
                           ↓ HTTP/REST ↓
┌─────────────────────────────────────────────────────────────────────────────┐
│                        ASP.NET CORE 8 API                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│  Controllers (PredictionsController, MatchesController, etc.)               │
│         ↓                                                                    │
│  Application Layer (Services: PredictionService, RankingService, etc.)      │
│         ↓                                                                    │
│  Domain Layer (Entities, Validations, Business Rules)                       │
│         ↓                                                                    │
│  Infrastructure Layer (Repositories, EF Context, External Services)         │
│         ↓ SQL ↓ NoSQL ↓                                                      │
└─────────────────────────────────────────────────────────────────────────────┘
         ↓                                  ↓                        ↓
┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐  ┌──────────┐
│   PostgreSQL     │  │   MongoDB        │  │  External APIs   │  │ AWS S3   │
│  - Users         │  │  - Minigame      │  │ - API-Football   │  │ - Assets │
│  - Predictions   │  │    scores        │  │ - Twilio         │  │ - Photos │
│  - Matches       │  │  - Quiz answers  │  │ - Expo Notif.    │  │          │
│  - Rankings      │  │                  │  │                  │  │          │
│  - Groups        │  │                  │  │                  │  │          │
└──────────────────┘  └──────────────────┘  └──────────────────┘  └──────────┘

How to Run

Prerequisites

  • Docker & Docker Compose (recommended for full stack)
  • .NET 8 SDK (for API development)
  • Node.js 18+ (for mobile/web/jobs development)
  • PostgreSQL client (psql, optional)
  • Expo CLI (for mobile: npm install -g expo-cli)

Development Environment

1. Start the full dev stack (API + PostgreSQL + MongoDB + MailHog):

docker compose --env-file ./environments/dev.env -f docker-compose.dev.yml up --build -d

This starts:

  • API on http://localhost:8080
  • PostgreSQL on localhost:5432 (user: postgres, password: palpitero)
  • pgAdmin on http://localhost:8081 (optional DB management)
  • MongoDB on localhost:27017
  • MailHog (mock SMTP) on http://localhost:8025

Healthcheck: curl http://localhost:8080/healthcheck

2. Configure environment variables:

# Copy and edit dev environment
cp environments/local.env.example environments/dev.env
# Update: DATABASE_CONNECTION_STRING, MONGO_HOST, API_KEYS, etc.

3. Run API migrations (first time):

cd server/api
dotnet ef migrations add Initial --project src/Infra --startup-project src/API
dotnet ef database update --startup-project src/API

Or use the init script if provided:

./scripts/init-db.sh  # Linux/Mac
.\scripts\init-db.ps1 # Windows

4. Start mobile app (Expo):

cd client/app
npm install
npm start

Then press:

  • w for Expo web
  • a for Android emulator
  • i for iOS simulator

5. Start web client:

cd client/web
npm install
npm run serve

Open http://localhost:8080 in your browser.

6. Run background jobs (optional, for testing):

cd server/bot
npm install
npm run future-matches     # Fetch matches
npm run past-matches       # Score predictions
npm run upcoming-matches   # Upcoming notifications
npm run prizes             # Calculate prizes

Production Deployment

See: docker-compose.prod.yml

docker compose --env-file ./environments/prod.env -f docker-compose.prod.yml up -d

Environment variables should include:

  • ASPNETCORE_ENVIRONMENT=Production
  • ConnectionStrings:DefaultConnection=<prod-postgres-uri>
  • mongoConnection:server=<prod-mongo-uri>
  • API keys (API-Football, Twilio, AWS S3, Expo)
  • SSL/TLS certificates (if reverse proxy)

CI/CD via GitHub Actions:

Testing

API unit tests (if present):

cd server/api/src
dotnet test

Mobile integration tests:

cd client/app
npm run test

Observability & Debugging

Logging

Health Checks

  • API healthcheck endpoint: GET http://localhost:8080/healthcheck
  • PostgreSQL: Via pgAdmin UI or psql client
  • MongoDB: mongo --host localhost --eval "db.adminCommand('ping')"

Debugging

API:

cd server/api
dotnet watch run  # Hot reload in development

Mobile:

# React Native debugger
npm start --dev
# Then open Expo dev menu (shake device or Ctrl+M)

Jobs:

cd server/bot
NODE_OPTIONS=--inspect npm run future-matches
# Debug in Chrome DevTools: chrome://inspect

Database Inspection

  • PostgreSQL: pgAdmin at http://localhost:8081 or psql CLI
  • MongoDB: MongoDB Compass (GUI tool) or mongo shell

Key Dependencies

Backend

Package Version Purpose
ASP.NET Core 8.0.8 REST API framework
Entity Framework Core 8.0.8 ORM for PostgreSQL
MediatR 12.4.0 Domain events & mediator pattern
AutoMapper 13.0.1 DTO mapping
FluentValidation 11.9.2 Input validation
JWT Bearer 8.0.8 JWT token validation
MongoDB.Driver 3.3.0 NoSQL database
Twilio 7.8.0 SMS integration
AWS SDK S3 3.7.402.12 File storage

Mobile

Package Version Purpose
expo 53.0.10 React Native framework
expo-router 5.0.7 File-based routing
react-native (via Expo) Native UI
axios 1.7.7 HTTP client
i18next 25.2.1 Localization
expo-notifications 0.31.3 Push notifications
react-native-elements 3.4.3 UI component library

Jobs

Package Version Purpose
node-cron 3.0.3 Job scheduling
axios 1.7.7 HTTP client (API-Football)
pg 8.12.0 PostgreSQL connection
amqplib 0.10.4 Message queue (if used)
whatsapp-web.js 1.26.0 WhatsApp integration (optional)

Environment Files

Key configuration files:

Required environment variables:

# Database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=<secure-password>
POSTGRES_DB=palpitero
POSTGRES_HOST=postgres

# MongoDB
MONGO_HOST_USERNAME=<username>
MONGO_HOST_PASSWORD=<secure-password>

# API Keys
API_FOOTBALL_KEY=<api-football.com-key>

# External Services
TWILIO_ACCOUNT_SID=<twilio-sid>
TWILIO_AUTH_TOKEN=<twilio-token>
AWS_ACCESS_KEY_ID=<aws-key>
AWS_SECRET_ACCESS_KEY=<aws-secret>
AWS_S3_BUCKET=<bucket-name>

# Expo
EXPO_PROJECT_ID=<expo-project-id>
EXPO_ACCESS_TOKEN=<expo-token>

# JWT
JWT_SECRET=<long-secure-secret>
JWT_EXPIRATION_HOURS=24

# Localization
DEFAULT_TIMEZONE=America/Sao_Paulo

# API
ASPNETCORE_ENVIRONMENT=Development
ASPNETCORE_EXPORT_PORT=8080

# Frontend
API_ENDPOINT=http://localhost:8080/  # or production URL

License

This software was developed by Alexandre Beato and is licensed by Koppler. Unauthorized use is illegal. For more information, check out the LICENSE file.

About

Palpitero FC lets Brazilian football fans predict match results, compete in rankings, and win prizes with no betting risks.

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages