Skip to content

farulivan/personal-wa-bot

Repository files navigation

personal-wa-bot

personal-wa-bot

A TypeScript WhatsApp bot for personal daily tracking and reminders.

Features · Quick Start · Commands · Configuration · Project Structure · Docs

GitHub Actions License Node TypeScript


Features

Workout Tracking — #workout

Log lift and cardio sessions with compact syntax, track streaks, and get daily group leaderboards.

#workout lift push up 20reps 4sets 10kg
#workout cardio run 30min 5km
#workout list
  • Explicit modes: lift and cardio
  • Configurable streak threshold (MIN_WORKOUTS_FOR_STREAK)
  • Paginated history with mode badges ([lift], [cardio])
  • Daily digest leaderboard in group chat
  • Monthly recap: on day 1 of each month, sends the previous month's Workout and Quran leaderboards to DIGEST_GROUP_ID
  • Undo last workout log within 5 minutes (#workout undo)
  • Leaderboard preview on demand (#workout leaderboard)

Quran Reading — #quran

Track daily pages, manage bookmarks, and get nightly group reminders.

#quran read 3
#quran mark 145
#quran list
  • Auto-accumulate multiple logs per day
  • Auto-advance bookmark after each read (skip with --no-mark)
  • Khatam detection — resets bookmark when passing page 604
  • Streak tracking and nightly reminder in group
  • Undo today's read within 5 minutes (#quran undo)
  • Leaderboard preview on demand (#quran leaderboard)

Sholat Schedule — #sholat

Fetch daily prayer times with location-aware caching.

#sholat --today
#sholat --today --location bandung
  • DB-cached schedules (fetched once per location per day)
  • Self-healing location catalog refresh on stale data

Personal Reminders — #remind

Set reminders with natural date/time input, delivered back to the source chat.

#remind tomorrow 9am Review proposal
#remind 2026-03-10 10:30 Submit report
#remind list
  • Flexible parsing: today, tomorrow, YYYY-MM-DD + 9am, HH:MM, 14
  • Delivered to the same chat (group or direct) where it was created
  • Safety limits: 200 char max text, 50 active reminders per user
  • Undo last reminder within a short window (#remind undo)

Tech Stack

Layer Technology
Runtime Node.js 20+ · TypeScript 5.x
WhatsApp whatsapp-web.js
Database PostgreSQL · Drizzle ORM
Testing Vitest
Linting ESLint · Prettier
Package Manager pnpm

Quick Start

Prerequisites

  • Node.js 20+
  • pnpm
  • PostgreSQL instance (local or remote)
  • Chromium dependencies (OS-dependent, only if running outside Docker)

Install and run

# 1. Install dependencies
pnpm install

# 2. Configure environment
cp .env.example .env
# Edit .env — fill DATABASE_URL and ALLOWED_NUMBERS at minimum

# 3. Build and start
pnpm build
pnpm start

On first run, scan the QR code shown in terminal to authenticate your WhatsApp session.

Docker

docker compose up --build

docker-compose.yml mounts .wwebjs_auth/ for session persistence and data/ for local storage.


Command Reference

Workout

Command Description
#workout lift push up 20reps 4sets 10kg Log a lift session (weight optional)
#workout lift pull up 8rep 5set Log bodyweight lift
#workout cardio run 30min 5km Log cardio (distance optional)
#workout cardio brisk walk 1hour Log cardio with hour unit
#workout list View paginated history
#workout list 2 View page 2
#workout undo Undo your most recent log (within 5 minutes)
#workout leaderboard Show today's group leaderboard
#workout help Show command help

Format rules: Reps accept rep/reps, sets accept set/sets, weight uses kg only, duration uses min/hour, distance uses km.

Quran

Command Description
#quran read 3 Log 3 pages read today
#quran read 3 --no-mark Log without advancing bookmark
#quran mark 145 Set bookmark to page 145
#quran mark Check current bookmark
#quran list View paginated reading history
#quran undo Undo today's most recent read (within 5 minutes)
#quran leaderboard Show today's group leaderboard
#quran help Show command help

Sholat

Command Description
#sholat / #sholat --today Today's schedule (default location)
#sholat --today --location bandung Specify location
#sholat help Show command help

Remind

Command Description
#remind 2026-03-10 10:30 Review proposal Set reminder with specific date
#remind today 9am Join standup Set reminder for today
#remind tomorrow 8:15 Prepare update Set reminder for tomorrow
#remind list View active reminders
#remind undo Undo last reminder (within a short window)
#remind help Show command help

Configuration

See .env.example for the full template.

Required variables
Variable Default Description
DATABASE_URL PostgreSQL connection URL
ALLOWED_NUMBERS "" Comma-separated phone allowlist (digits only, e.g. 6281234567890)
DIGEST_GROUP_ID "" Target group for scheduled digests. Scheduler disabled if empty.
DEBUG false Enable debug logs (true/1)
Scheduling
Variable Default Description
USER_TIMEZONE_OFFSET_MINUTES 420 UTC offset in minutes (UTC+7 = 420)
DAILY_DIGEST_HOUR 8 Workout digest hour (24h, user timezone)
DAILY_DIGEST_MINUTE 0 Workout digest minute
QURAN_REMINDER_HOUR 22 Quran reminder hour (24h, user timezone)
QURAN_REMINDER_MINUTE 0 Quran reminder minute
MONTHLY_DIGEST_HOUR 8 Monthly recap hour (day 1, 24h, user timezone)
MONTHLY_DIGEST_MINUTE 0 Monthly recap minute
Feature behavior
Variable Default Description
MIN_WORKOUTS_FOR_STREAK 3 Workouts/day to count as a streak day
WORKOUT_LIST_LIMIT 10 Rows per page for #workout list
QURAN_LIST_LIMIT 10 Rows per page for #quran list
REMIND_LIST_LIMIT 10 Rows per page for #remind list
QURAN_RAMADHAN_COUNT_ENABLED false Show Ramadhan total in #quran list
QURAN_RAMADHAN_START_DATE Ramadhan start (YYYY-MM-DD, inclusive)
QURAN_RAMADHAN_END_DATE Ramadhan end (YYYY-MM-DD, inclusive)
SHOLAT_DEFAULT_LOCATION KAB. BOGOR Default prayer schedule location
SHOLAT_TIMEZONE Asia/Jakarta IANA timezone for sholat date calc
Deployment
Variable Default Description
PUPPETEER_EXECUTABLE_PATH Override Chromium binary path
RAILWAY_VOLUME_MOUNT_PATH Override WA auth storage path
Timezone and date logic

Timestamps are stored in UTC. User-local day boundaries are calculated using USER_TIMEZONE_OFFSET_MINUTES.

Example: With USER_TIMEZONE_OFFSET_MINUTES=420 (UTC+7), a log at 2026-02-21T17:30:00Z becomes local 2026-02-22 00:30 and belongs to Feb 22.

Scheduled jobs use the same offset, so digest/reminder timing is always consistent with user-local time. Reminder input (#remind) is interpreted in this timezone, then stored as UTC.

Ramadhan counter: When QURAN_RAMADHAN_COUNT_ENABLED=true, #quran list shows a Ramadhan total line. Date range is inclusive on both ends, using user-local day comparison.


Project Structure

src/
├── index.ts              # Composition root — wires all dependencies
├── config/env.ts         # Centralized env parsing
├── app/                  # Application layer (router, handler, auth, scheduler)
├── adapters/whatsapp/    # WhatsApp adapter (ports, gateway, ID helpers)
├── modules/
│   ├── workouts/         # Workout tracking module
│   ├── quran/            # Quran reading module
│   ├── sholat/           # Prayer schedule module
│   ├── remind/           # Reminder module
│   └── users/            # User identity management
├── db/                   # Drizzle connection, migrations, schema aggregator
└── shared/               # Shared utilities (Result type)

Each module follows a consistent internal structure:

modules/<name>/
├── index.ts              # Registration factory (module's public API)
├── <name>Parser.ts       # Pure input parsing → Result<T>
├── <name>Service.ts      # Business logic (depends on repository interface)
├── <name>Controller.ts   # Thin handler: invocation → service → presenter
├── <name>Presenter.ts    # Pure string formatting
└── infra/
    ├── <name>Repository.ts         # Interface (contract)
    ├── drizzle<Name>Repository.ts  # Implementation (Drizzle queries)
    └── schema.ts                   # Table definition

See the Architecture Guide for a full walkthrough of how the layers connect and how to add a new module.


Development

pnpm dev              # TypeScript watch mode
pnpm build            # Compile + copy migrations
pnpm verify           # Type-check + lint (tsc --noEmit && eslint)
pnpm test             # Run unit tests
pnpm lint:fix         # Auto-fix lint issues
pnpm format           # Format with Prettier

Internal Behavior

  • Group chats: bot responds only when mentioned or message starts with #.
  • Auth: only phone numbers in ALLOWED_NUMBERS can execute commands.
  • Identity: user IDs are normalized before persistence to handle WA ID format variations.
  • Remind scheduler: runs independently after WA client is ready, polls every 30s.
  • Digest/Quran scheduler: runs only when DIGEST_GROUP_ID is configured.

Security

  • Keep .env out of version control (already in .gitignore).
  • Restrict access via ALLOWED_NUMBERS — no allowlist means no one can use the bot.
  • Persist .wwebjs_auth/ and data/ in production environments.
  • Do not share terminal logs publicly (may contain operational details).

Troubleshooting

Bot does not respond
  • Check sender number is in ALLOWED_NUMBERS
  • In groups, ensure message starts with # or bot is mentioned
  • Set DEBUG=true and inspect logs
Scheduler not running
  • Digest/Quran jobs: verify DIGEST_GROUP_ID is set and timezone/hour/minute values are correct
  • Reminders: ensure WA client reached ready state; check DB for pending reminders (sent_at IS NULL, scheduled_at <= now)
Authentication issues
  • Ensure auth path is writable (.wwebjs_auth/ or RAILWAY_VOLUME_MOUNT_PATH)
  • Delete auth folder and rescan QR if session is corrupted

Documentation

Document Description
Architecture Guide How the codebase is structured, key patterns, and step-by-step guide for adding new features

License

MIT

About

A TypeScript WhatsApp bot for personal daily tracking and reminders.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors