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.