Skip to content

Latest commit

 

History

History
123 lines (90 loc) · 11.8 KB

File metadata and controls

123 lines (90 loc) · 11.8 KB

Global prayer bot

This directory is a separate application derived from the existing city bots. It has its own Go module, container image, Cloud Run services, Terraform state, Telegram token, Secret Manager entries, and PostgreSQL schema. Nothing under global/ imports or changes the legacy runtime.

Engineering documentation

Start with docs/README.md before changing the global bot. It links the system architecture, package ownership, request flows, data model, reminder delivery semantics, runtime/deployment topology, and operational runbook. Architectural or persistence changes should update the owning document in the same pull request.

What is implemented

  • Location onboarding from Telegram coordinates, with group changes restricted to group administrators.
  • Google Time Zone and reverse-geocoding lookups only when the location changes.
  • Local calculation of prayer times with MWL, Egyptian, Umm al-Qura, Karachi, ISNA, Diyanet, Kemenag, MUIS, and JAKIM methods.
  • Shafii/Hanafi Asr selection, three high-latitude rules, and per-prayer minute adjustments.
  • A persistent two-column Telegram menu for today, tomorrow, the next prayer, location, settings, reminders, language, and help.
  • A Telegram Mini App, opened from the bot menu or an optional Telegram home-screen shortcut, for today/tomorrow schedules, location, calculation settings, Hijri correction, and all reminder toggles without typed commands.
  • A privacy-safe, per-user 48-hour Mini App cache for instant startup and read-only access to saved schedules, Qibla data, and prayer-card sharing during temporary network failures.
  • Inline button pickers for calculation method, madhab, high-latitude rule, per-prayer adjustments, reminder state, and language. The equivalent typed commands remain available.
  • Localized messages, reply keyboards, prayer names, dates, Mini App, and reminder deliveries in English, Arabic, Spanish, French, Russian, Turkish, Uzbek, and Tatar. The public Telegram bot name and description remain stable for every user.
  • Gregorian and calculated Umm al-Qura Hijri dates on every daily schedule, with a per-chat moon-sighting correction from -2 to +2 days.
  • The next three Islamic occasions in the Mini App and matching all-day events in the private rolling calendar, using the same corrected Hijri date.
  • A curated, localized occasion catalog covering major dates, voluntary fasting opportunities, and commonly observed dates, with cautious explanatory text and Quran/Hadith source links where available.
  • Three independent, opt-in occasion reminder groups delivered at 20:00 on the preceding local evening.
  • Opt-in weekly reminders for Monday/Thursday voluntary fasting (20:00 on the preceding evening) and reading Surah Al-Kahf on Friday (09:00), scheduled in the saved local timezone.
  • Configurable pre-prayer reminders at 5, 10, 15, 20, 30, 45, or 60 minutes before each obligatory prayer, followed by the normal prayer-time notification.
  • Category-aware notification cleanup: a new prayer notice replaces the preceding prayer/pre-prayer message, weekly categories are independent, and every reminder expires within Telegram's deletion window.
  • A Qibla tool that calculates the initial great-circle bearing and distance to the Kaaba from the saved rounded coordinates, with optional live compass orientation on supported Telegram clients.
  • A revocable private Google Calendar subscription that serves a localized rolling 30-day prayer feed and automatically reflects the saved location and calculation settings when Google refreshes it.
  • Localized 1080×1350 prayer cards generated entirely in the Mini App and shared through the device share sheet; Telegram WebViews without file sharing send the PNG to the user's bot chat for reliable saving or forwarding.
  • An embedded welcome illustration sent on /start and a generated bot avatar installed during profile synchronization.
  • A localized feedback and bug-report flow that accepts text or screenshots in a private chat and delivers them directly to the configured owner with the sender's disclosed Telegram identity.
  • An owner-only /admin dashboard with aggregate user activity, onboarding, language, calculation-method, reminder-adoption, queue, and delivery-health metrics.
  • Indexed reminder scheduling through Cloud Scheduler, an outbox, Cloud Tasks, a private sender service, leases, and delivery idempotency keys.
  • Dedicated global_bot_testing and global_bot_production PostgreSQL schemas, each with its own Goose migration table.

The initial UI language follows the user's Telegram language when supported and otherwise falls back to English. A language selected inside the bot is persisted and is not overwritten by later Telegram updates.

Hijri dates use the calculated Umm al-Qura calendar. Because official local moon-sighting dates can differ by a day or two, users can correct the date under Settings → Hijri date correction. The correction shifts Hijri labels and Islamic occasion dates consistently; it never shifts prayer calculations.

Owner dashboard and feedback

The Telegram account configured by GLOBAL_OWNER_ID can open the private owner dashboard with /admin or the backward-compatible /status command. The command is intentionally absent from the public command menu, is ignored for every other user, and is unavailable in groups. Its inline buttons show aggregate metrics only; the dashboard never lists Telegram IDs, coordinates, or individual user records.

Feedback arrives in the owner's private bot chat as a metadata message followed by a copy of the user's original text or screenshot. A Contact user button opens the sender's Telegram profile. Replies typed inside the bot chat are not forwarded, so contact the sender through that button or the linked username.

Services

Service Access Responsibility
webhook Public URL; webhook protected by Telegram's secret header, Mini App API protected by signed init data Commands, Mini App, location setup, calculation settings
dispatch Cloud Scheduler service account only Claim due indexed schedules and create Cloud Tasks
sender Cloud Tasks service account only Idempotent Telegram delivery, category cleanup, and next-occurrence planning

The three services use one immutable image and select /webhook, /dispatch, or /send as the command. The webhook binary embeds the Mini App and serves it at /app/, so the feature does not add another Cloud Run service, container image, database, migration, or secret. Offline snapshots remain on the user's device, and prayer cards are rendered in the browser. A card that cannot use the device share sheet is uploaded directly to Telegram as a photo in the user's bot chat and is not retained by the service; neither feature adds server storage or scheduled work.

Calendar subscriptions use a random private bearer URL created only after the Mini App session has been authenticated. The URL exposes neither the Telegram user ID nor the bot token and can be revoked from the Mini App. Each fetch calculates today and the following 29 local days, including prayer times and Islamic occasions, so no daily cron or stored calendar events are required. Google controls when subscribed calendars refresh, so updates are not guaranteed to appear exactly at local midnight. Qibla calculations and calendar generation use the existing saved profile and local calculation engines, so neither feature adds an external API call from the bot or a recurring job.

Testing and production secrets

The global workflow reuses the existing GitHub environments: logical testing deployments read secrets from dev, and logical production deployments read secrets from prod. No duplicate infrastructure environments or credentials are required.

Secret dev value for testing prod value for production
GLOBAL_BOT_TOKEN Testing Telegram bot token Production Telegram bot token
GLOBAL_WEBHOOK_SECRET Testing webhook secret Production webhook secret
GLOBAL_OWNER_ID Testing owner ID Production owner ID
GCP_PROJECT_ID Existing dev value Existing prod value
GCP_SA_KEY Existing dev value Existing prod value
GCP_TFSTATE_BUCKET Existing dev value Existing prod value
SUPABASE_DB_URL Existing database URL Existing database URL
SUPABASE_DB_DIRECT_URL Existing direct database URL Existing direct database URL

Only the three global-bot values are new; add them to the existing environments:

gh secret set GLOBAL_BOT_TOKEN --env dev
gh secret set GLOBAL_WEBHOOK_SECRET --env dev
gh secret set GLOBAL_OWNER_ID --env dev

gh secret set GLOBAL_BOT_TOKEN --env prod
gh secret set GLOBAL_WEBHOOK_SECRET --env prod
gh secret set GLOBAL_OWNER_ID --env prod

The webhook secret must be 1-256 characters and contain only letters, numbers, _, or -. During deployment, the workflow copies the selected values into environment-specific Secret Manager secrets such as global-prayer-bot-token-testing and global-prayer-bot-token-production; values are never shared between environments. Testing and production may reuse the same database URL because their tables and migration history live in separate schemas. The global workflow never uses the legacy APP_CONFIG.

The existing deployment service account may need additional roles that the legacy Cloud Functions deployment did not use: roles/run.admin, roles/artifactregistry.admin, roles/cloudtasks.admin, roles/cloudscheduler.admin, roles/secretmanager.admin, roles/serviceusage.apiKeysAdmin, roles/serviceusage.serviceUsageAdmin, roles/iam.serviceAccountAdmin, roles/iam.serviceAccountUser, and roles/resourcemanager.projectIamAdmin. It also needs object access to the existing Terraform state bucket. Scope these roles to the selected testing/production project (and the state bucket) rather than organization-wide.

Google Maps key

Terraform enables the Time Zone and Geocoding APIs, creates a dedicated API key restricted to those two APIs, creates a Secret Manager secret, and injects the key only into the webhook service. No manually created Maps key is required.

The key has API restrictions but no client-IP restriction because Cloud Run does not have a stable egress IP by default. If static egress is added later through a VPC connector and Cloud NAT, add that NAT IP as an application restriction. The Terraform state contains the sensitive key and database URL; keep the existing state bucket access tightly restricted.

Local checks

cd global
make check
terraform -chdir=infra/gcp fmt -check -recursive
terraform -chdir=infra/gcp init -backend=false
terraform -chdir=infra/gcp validate

For migrations, use the existing direct database connection but the global migration table:

export GLOBAL_DB_SCHEMA=global_bot_testing
go run ./cmd/bootstrapdb
goose -dir migrations -table="${GLOBAL_DB_SCHEMA}.goose_db_version" postgres "$DATABASE_URL" up

The bootstrap command only creates the selected empty global schema. GLOBAL_DB_SCHEMA accepts global_bot_testing or global_bot_production. Bootstrap must happen before Goose's first run because Goose creates its schema-qualified version table before applying migration Up statements.

Deployment

Run the separate Deploy global prayer bot GitHub workflow and choose testing or production. It uses a distinct state prefix (prayer-bot/global-testing or prayer-bot/global-production), migrates the matching global_bot_testing or global_bot_production schema, builds the global image, provisions the global resources, and then configures the selected Telegram webhook, Mini App menu button, stable public profile, command menu, and avatar. The Mini App URL is derived from the environment's existing webhook URL; no new GitHub variable is required.

The workflow is intentionally manual until the new token, secrets, API quotas, privacy text, and prayer-time samples are approved through the logical testing deployment.