A Rust application that helps you stay in touch with friends by tracking calendar meetings and sending automated reminders via Telegram and WhatsApp.
Status: β Production Ready - Fully automated with GitHub Actions + Firebase state
MateCheck connects to your Google Calendar, identifies meetings with friends, and sends you Telegram reminders when you haven't seen someone in a while. It runs automatically every day via GitHub Actions.
- Google Calendar Integration - Fetches events with OAuth 2.0 authentication
- Smart Friend Matching - Matches events to friends by:
- Email addresses (primary method)
- Event titles with name/alias matching (fallback)
- All-Day Event Support - Tracks both timed and all-day calendar events
- Recurring Event Filtering - Automatically filters out birthdays and anniversaries
- Firestore Configuration - Store friends config in Firebase Firestore
- Web UI - Mobile-responsive web interface for managing friends
- Add, edit, and delete friends via intuitive UI
- No YAML editing required
- Deployed on GitHub Pages
- Google Sign-In authentication
- Automatic YAML Fallback - Seamlessly falls back to local friends.yaml if Firestore unavailable
- Automatic Early Warnings - Reminds you 15% before your target frequency
- 10 days β remind at day 8 (2 days early)
- 30 days β remind at day 25 (5 days early)
- 45 days β remind at day 38 (7 days early)
- Future Meeting Awareness - Skips reminders if meeting already scheduled
- Friend Aliases - Match calendar events with nicknames (e.g., "Lou" matches "Louise")
- Snooze Functionality β NEW - Temporarily pause reminders for specific friends
- Click inline buttons in Telegram: 3 days, 1 week, or 2 weeks
- Powered by Firebase Firestore + Cloud Functions
- Fail-open design (works even if Firebase is unavailable)
- Do Not Disturb Mode - Automatically pauses ALL reminders during specific periods
- Create all-day calendar events with π emoji or [DND] text
- Examples: "π Vacation in Paris", "[DND] Focus Week"
- Works with single-day and multi-day events
- Only all-day events count (timed events ignored)
- Telegram Integration - Sends formatted reminders with clickable links
- WhatsApp Support - Creates WhatsApp deep links for friends without Telegram
- Smart Fallback - Telegram username β WhatsApp β plain name
- GitHub Actions - Runs automatically on schedule
- Weekdays: 8:00 AM Berlin time
- Weekends: 9:30 AM Berlin time
- Manual Testing - Can be triggered manually for testing
- Language: Rust π¦ (2021 edition) + TypeScript (Cloud Functions)
- APIs: Google Calendar API v3, Telegram Bot API
- Database: Firebase Firestore (state persistence + config storage)
- Backend: Firebase Cloud Functions (webhook for button callbacks)
- Frontend: Vanilla JavaScript + Firebase SDK (web UI)
- Key Crates: tokio, serde, chrono, clap, reqwest, firestore
- Auth: OAuth 2.0 for Google Calendar, Firebase Service Account, Google Sign-In (web UI)
- CI/CD: GitHub Actions
- Hosting: GitHub Pages (web UI)
- Tests: 79 passing tests (Rust)
matecheck/
βββ src/
β βββ main.rs # CLI entry point
β βββ config.rs # Friend configuration loader (Firestore + YAML)
β βββ calendar/ # Google Calendar integration
β β βββ client.rs # OAuth & API client
β β βββ types.rs # Event types
β β βββ dnd.rs # Do Not Disturb detection
β βββ firestore/ # Firebase Firestore integration
β β βββ client.rs # Firestore connection
β β βββ snoozes.rs # Snooze repository (CRUD)
β β βββ types.rs # Firestore data types
β βββ matcher.rs # Event-to-friend matching logic
β βββ reminder/
β β βββ engine.rs # Reminder calculation logic
β βββ telegram/ # Telegram integration
β βββ client.rs # Bot API client
β βββ formatter.rs # Message formatting + inline buttons
βββ docs/ # Web UI (GitHub Pages)
β βββ index.html # Friends management interface
β βββ README.md # Web UI setup instructions
β βββ SETUP.md # Deployment guide
βββ functions/ # Firebase Cloud Functions (TypeScript)
β βββ src/
β β βββ index.ts # Webhook handler for button callbacks
β βββ package.json
β βββ tsconfig.json
βββ .github/
β βββ workflows/
β βββ daily-check.yml # Automated deployment
βββ friends.yaml # Fallback config (gitignored, optional)
βββ friends.example.yaml # Example configuration
βββ firebase.json # Firebase configuration
βββ Cargo.toml # Rust dependencies
- Rust (latest stable)
- Node.js 22+ (for Firebase Functions)
- Google Calendar API credentials
- Telegram bot token
- Firebase project (free tier)
- GitHub account (for automation)
-
Clone and configure:
git clone <your-repo> cd matecheck cp friends.example.yaml friends.yaml # Edit friends.yaml with your friends
-
Set up Google Calendar API:
- Create a project in Google Cloud Console
- Enable Google Calendar API
- Create OAuth 2.0 credentials (Desktop app)
- Download as
credentials.jsonin project root - Run once locally to authenticate:
cargo run -- --debug
-
Set up Telegram Bot:
- Create bot via @BotFather
- Get your chat ID:
cargo run --bin get_chat_id - Create
.envfile:TELEGRAM_BOT_TOKEN=your_bot_token TELEGRAM_CHAT_ID=your_chat_id
-
Run locally:
cargo run # Normal run cargo run -- --debug # Debug mode with verbose output cargo run -- --test-telegram # Test Telegram integration
-
Push code to GitHub:
git push origin master
-
Set up Firebase (optional, for snooze feature):
- Create Firebase project
- Enable Firestore Database
- Enable billing (required for Secret Manager, but stays on free tier)
- Create service account, download as
service-account.json - Deploy Cloud Function:
cd functions && npm install && firebase deploy --only functions - Set Telegram webhook to Cloud Function URL
-
Add repository secrets (Settings β Secrets β Actions):
GOOGLE_CREDENTIALS- Content ofcredentials.jsonGOOGLE_OAUTH_TOKEN- Content oftoken.json(refresh tokens last 6+ months)TELEGRAM_BOT_TOKEN- Your bot tokenTELEGRAM_CHAT_ID- Your chat IDFRIENDS_CONFIG- Content offriends.yamlFIREBASE_SERVICE_ACCOUNT- Content ofservice-account.json(if using snooze)
-
Test workflow:
- Go to Actions tab
- Select "Daily Friend Reminder Check"
- Click "Run workflow"
-
Done! Reminders run automatically on schedule.
Deploy the friends management interface to GitHub Pages:
-
Enable GitHub Pages:
- Go to repo Settings β Pages
- Source: Deploy from a branch
- Branch:
master, Folder:/docs - Save and wait 1-2 minutes
-
Configure Firebase for web access:
- Follow the detailed setup guide in
docs/SETUP.md - Enable Google Sign-In authentication
- Update Firestore security rules
- Add your GitHub Pages domain to authorized domains
- Follow the detailed setup guide in
-
Access your web UI:
- Visit
https://YOUR_USERNAME.github.io/matecheck/ - Sign in with Google
- Manage friends through the interface
- Visit
See docs/README.md for complete setup instructions.
MateCheck supports two configuration methods:
- Firestore (Recommended) - Store friends in Firebase Firestore, edit via web UI
- YAML (Fallback) - Local friends.yaml file (automatically used if Firestore unavailable)
The easiest way to manage friends is through the web UI:
- Deploy web UI to GitHub Pages (see docs/SETUP.md)
- Visit your GitHub Pages URL
- Sign in with Google
- Add/edit/delete friends via the interface
Changes take effect immediately - no deployment needed!
friends:
- id: "alice"
name: "Alice Smith"
email: "alice@example.com"
telegram_username: "alice_tg"
frequency_days: 30
- id: "bob"
name: "Bob Johnson"
email: "bob@example.com"
whatsapp_phone: "+1 234 567 8900" # For friends without Telegram
aliases: ["Bobby"] # Match "Bobby" in calendar
frequency_days: 14
- id: "charlie"
name: "Charlie"
frequency_days: 60 # No contact info = plain nameid(required) - Unique identifiername(required) - Friend's display nameemail(optional) - For calendar matchingtelegram_username(optional) - Creates t.me/username linkwhatsapp_phone(optional) - Creates WhatsApp link (+ and spaces auto-stripped)aliases(optional) - Alternative names for calendar matchingfrequency_days(required) - How often you want to meet (in days)
- Loads Active Snoozes - Queries Firestore for snoozed friends (fail-open if unavailable)
- Fetches Calendar Events - Gets events from last 90 days + future events
- Checks Do Not Disturb - Exits early if DND event detected (skips all reminders)
- Matches Friends - Identifies which events involved which friends
- Calculates Last Meeting - Finds most recent past meeting per friend
- Checks Future Meetings - Looks for upcoming scheduled meetings
- Applies Smart Logic:
- Filters out snoozed friends
- Reminds at 85% of target frequency (15% buffer)
- Skips reminder if meeting already scheduled
- Ignores recurring events (birthdays)
- Sends Telegram Message - Formatted list with inline snooze buttons
- Button Callback - Cloud Function handles button clicks, updates Firestore
cargo test # All tests
cargo test --lib # Library tests only
cargo test test_name # Specific testcargo run --bin get_chat_id # Get your Telegram chat IDMIT License - See LICENSE file
This project was built as a learning exercise to understand Rust coming from a Go background. It covers:
- Rust ownership, borrowing, and lifetimes
- Async/await with tokio
- OAuth 2.0 authentication
- API integration (Google Calendar, Telegram, Firestore)
- Firebase Cloud Functions (TypeScript)
- State persistence with Firestore
- GitHub Actions CI/CD
- Error handling with Result types
- Testing and test-driven development
- Graceful degradation (fail-open patterns)