A Laravel-based stock portfolio tracking application with Telegram bot integration, automated daily reports, and real-time stock price updates via AlphaVantage API.
- Telegram Bot Integration: Search stocks, add to portfolio, get instant recaps
- Real-time Stock Prices: Powered by AlphaVantage API
- Automated Reports: Daily email and Telegram notifications with P/L analysis
- Performance Tracking: Daily, MTD, and YTD performance metrics
- RESTful API: Full CRUD operations for portfolio management
- Cloud-Ready: Optimized for Google Cloud Run deployment
- Type-Safe: Strict PHP 8.4 typing with
declare(strict_types=1) - Tested: Comprehensive Pest test suite
For detailed information on configuration and deployment, please refer to the following guides:
- Deployment Guide - Standard VPS and Docker deployment.
- Google Cloud Run Guide - Serverless deployment steps.
- Google Drive Setup - How to configure cloud storage for reports.
- Implementation Report - Project status and completed tasks.
- Docker & Docker Compose
- PHP 8.4+
- PostgreSQL (via Supabase)
- AlphaVantage API Key
- Telegram Bot Token (optional)
-
Clone and setup:
git clone <repository-url> cd stock-market-app
-
Configure environment:
Note: The files
.env,.env.staging, and.env.productionare committed to the repository with dummy values to prevent exposing sensitive credentials on GitHub.Edit
.env(or.env.staging/.env.productionbased on your target) and set your real credentials:DB_HOST,DB_USERNAME,DB_PASSWORD(Supabase credentials)ALPHA_VANTAGE_API_KEYTELEGRAM_BOT_TOKEN(optional)CRON_SECRET(generate a random string)
-
Start the application:
./run staging
-
Run migrations:
./sail artisan migrate
-
Access the app:
-
Start Queue Worker (Required for pricing & reports):
./sail artisan queue:work
# Start staging environment
./run staging
# Start production environment
./run production
# Run artisan commands
./sail artisan <command>
# Run tests
./test
# Manual stock fetch
./sail artisan stocks:fetch
# Generate daily report
./sail artisan report:daily
# Seed test data (Safe for staging/local)
./sail artisan db:seed-test/start- Welcome message and command list/search <symbol>- Search for stock symbols (e.g.,/search AAPL)/add <symbol> <quantity>- Add stocks to portfolio (e.g.,/add AAPL 10)/recap- Get current portfolio summary with P/L
# Webhook now uses your bot token as a secret path for security
curl "https://api.telegram.org/bot<YOUR_TOKEN>/setWebhook?url=https://your-domain.com/api/telegram/webhook/<YOUR_TOKEN>"GET /api/portfolio # List all holdings
POST /api/portfolio # Add transaction
DELETE /api/portfolio/{id} # Remove transactionGET /api/cron/fetch-stocks # Trigger stock price update
GET /api/cron/daily-report # Trigger daily report generation- Install Google Cloud SDK
- Authenticate:
gcloud auth login - Create a GCP project
- Enable APIs:
gcloud services enable run.googleapis.com gcloud services enable cloudscheduler.googleapis.com gcloud services enable containerregistry.googleapis.com
-
Update configuration: Edit
deploy.shand setPROJECT_ID -
Configure production environment: The
.env.productionfile contains dummy values. Edit it with your real production credentials. -
Deploy to Cloud Run:
./deploy.sh production
-
Setup Cloud Scheduler (replaces cron):
./scheduler-setup.sh production
-
Cloud Run: 2M requests/month FREE
- Expected usage: ~3,000 requests/month
- Cost: $0/month
-
Cloud Scheduler: 3 jobs/month FREE
- We use 2 jobs
- Cost: $0/month
-
Supabase: 500MB database FREE
- Expected usage: <100MB
- Cost: $0/month
Total estimated cost: $0/month β
# Run all tests
./test
# Run specific test file
./test tests/Feature/StockServiceTest.php
# Run with coverage
./sail artisan test --coverageTo get up and running quickly with a consistent environment, you can use the built-in test data seeder.
Warning
This command will TRUNCATE all data in the following tables: users, tickers, transactions, daily_metrics, settings, and personal_access_tokens. Use it only in development or staging environments.
./sail artisan db:seed-testThe seeder provides:
- Admin User:
admin@example.com/password - Sample Users: 5 additional random users
- Tickers: 10 active stock symbols
- Daily Metrics: 30 days of historical data per ticker
- Transactions: 15 transactions per user
- Default Settings: Pre-configured application settings
For testing purposes, you can link your Telegram account to any existing user ID from the database using the /start command. This allows you to "impersonate" a specific user and view their portfolio.
- Find the UUID of the user you want to link (e.g., from the
userstable or seeder output). - In Telegram, send:
/start <user_uuid>
Note
If the Telegram ID is already linked to another user, it will be automatically moved to the specified UUID to maintain the uniqueness of the telegram_id field.
- β Stock Service (API integration, error handling)
- β Report Service (daily/MTD/YTD calculations)
- β Transaction Service (CRUD, holdings calculation)
- β Market Hours Service (timezone handling)
app/
βββ Console/Commands/ # Artisan commands
β βββ FetchStockData.php
β βββ GenerateDailyReport.php
βββ Http/
β βββ Controllers/ # API & Telegram controllers
β βββ Middleware/ # Cron authentication
βββ Models/ # Eloquent models
β βββ User.php
β βββ Ticker.php
β βββ Transaction.php
β βββ DailyMetric.php
βββ Services/ # Business logic
β βββ AlphaVantageService.php
β βββ TelegramService.php
β βββ StockService.php
β βββ ReportService.php
β βββ TransactionService.php
β βββ MetricService.php
β βββ MarketHoursService.php
βββ Mail/
βββ DailyPortfolioReport.php
database/
βββ migrations/ # Database schema
βββ factories/ # Model factories for testing
tests/
βββ Feature/ # Integration tests
βββ Unit/ # Unit tests
- Cron endpoints protected by bearer token or OIDC (Cloud Run)
- API endpoints protected by Laravel Sanctum
- Database connections use SSL in production
- Passwords hashed with bcrypt
- CSRF protection on web routes
Daily reports are sent via email with:
- Portfolio summary
- Daily P/L per ticker
- Month-to-Date performance
- Year-to-Date performance
- CSV attachment with detailed data
Configure SMTP in .env:
MAIL_MAILER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=your-api-key- Verify Supabase credentials in
.env - Check if Supabase project is active (not paused)
- Ensure SSL mode is correct (
preferfor staging,requirefor production)
- Verify
ALPHA_VANTAGE_API_KEYis valid - Check API rate limits (5 requests/minute for free tier)
- Ensure market hours check is working
- Verify webhook is set correctly
- Check
TELEGRAM_BOT_TOKENin.env - Review logs:
./sail artisan log:tail
This project is open-source and available under the MIT License.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Write tests for new features
- Submit a pull request
For issues and questions, please open a GitHub issue.
Built with β€οΈ using Laravel 12, PHP 8.4, and modern senior best practices.