Skip to content

User Flow

Onboarding

One-time setup before using any command.

1. User opens: https://t.me/ZentrFinanceBot?start=onboard

2. Bot replies with:
   - Google OAuth link (scope: spreadsheets only — NOT full Drive)
   - Link to copy the template Sheet

3. User clicks OAuth link → Google consent screen
   - Google redirects to: https://<worker>/auth/callback?code=…&state={chatId}

4. Worker exchanges code for refresh token
   - Stores in KV under "pending_token:{chatId}" (TTL 10 min)
   - Returns HTML: "Authorization successful — return to Telegram"

5. User copies template Sheet from link → gets Spreadsheet ID from URL

6. User sends: /config SHEET_ID
   - Worker reads refresh token from KV
   - Saves to D1: {chatId, sheetId, refreshToken, locale, plan='free'}
   - Bot confirms: "✅ Setup complete!"

OAuth Token Lifecycle

  • Refresh tokens stored long-term in D1 (users.refresh_token)
  • Access tokens short-lived (1h) — SheetsAuth.getAccessToken() caches in KV; silently refreshes on expiry
  • pending_token:{chatId} KV entry has 10-minute TTL; if user takes longer, must restart OAuth flow

Bot Commands

Transaction Commands

/expense  AMOUNT DESCRIPTION [-c CATEGORY] [-a ACCOUNT] [-s STATUS]
/income   AMOUNT DESCRIPTION [-c CATEGORY] [-a ACCOUNT] [-s STATUS]
/investment AMOUNT DESCRIPTION [-c CATEGORY] [-a ACCOUNT]
/retrieval  AMOUNT DESCRIPTION [-a ACCOUNT]

Flag parsing rules: - Everything between amount and first flag is the description - Flags can appear in any order - -c category must exist in user's Budgets sheet (validated live) - -a account must be one of eight valid accounts (validated from fixed list) - -s status must be a valid TransactionStatus; if omitted, default derived from type - Unknown -c or -a values rejected with localised error listing valid options

Listing & Settling

/open              List all Pending / Scheduled / Planned / Deferred transactions
/settle UUID       Mark transaction as Paid/Received, update date to today

Utility Commands

/accounts          List valid account names
/concepts          List valid category names (from user's Budgets sheet)
/csv               Send Transactions sheet as a CSV file attachment

Automated Digests

Sent automatically — users do not trigger them.

Daily Digest (0 8 * * *)

Sent every morning at 08:00. Contains: - Expenses from yesterday (itemised: description, category, amount) - Income from yesterday - Net balance for yesterday - Per-diem real vs ideal (based on current period) - Available budget remaining in the period - Days until next payday

Weekly Summary (0 8 * * 1)

Sent every Monday at 08:00. Contains: - Total spent / income / balance for last Mon–Sun - Breakdown by category (sorted descending) - Breakdown by day of week - Per-diem real average vs ideal at week start (skipped if payday fell within the week) - Desired savings for the period (from _Cobros sheet) - 3–4 sentence AI analysis via Gemini (in the user's locale)

Deferred Settlement (0 7 * * *)

Finds all Deferred transactions whose date ≤ today and auto-settles them (Paid/Received). Sends a confirmation count to each affected user.


Transaction Status Lifecycle

/expense (default) → [Paid]

/expense -s Pending → [Pending] ──── /settle UUID ──────► [Paid/Received]

/expense -s Deferred → [Deferred] ──── cron 07:00 (date ≤ today) ──► [Paid]

/expense -s Scheduled → [Scheduled] ──── /settle UUID ──► [Paid]
/expense -s Planned  → [Planned]    ──── /settle UUID ──► [Paid]

Scheduled and Planned appear in /open and can be manually settled. Deferred is auto-settled by the nightly cron.