Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Invoice and Expense Automation with AI Analysis

Local-first finance automation for a creator or small business team.

This repo is built for one specific operating model:

  • Telegram is the control surface
  • Notion is the finance ledger
  • SQLite is local bot state only
  • Codex CLI is the optional AI layer
  • Local PDF rendering generates invoices from code

There is no hosted backend requirement.

What This Repo Is

This system helps you:

  • log won deals
  • reserve invoice numbers
  • finalize invoice details later
  • mark payments received
  • upload receipts and draft expenses
  • approve sensitive ledger writes
  • generate weekly summaries
  • ask for finance insights from the ledger

What This Repo Is Not

  • not a Google Sheets system
  • not a Telegram webhook service
  • not a hosted SaaS
  • not an OpenAI API integration
  • not a replacement for your local Notion workspace

Current Architecture

Telegram
  -> FinanceTelegramBot
    -> FinanceMessageParser
    -> ReceiptOcrService
    -> FinanceService
      -> NotionFinanceRepository
      -> InvoiceRenderer
      -> CodexCliClient (optional)
      -> LocalStore (SQLite)

Major Components

src/index.ts

Boot entrypoint.

It:

  • loads .env
  • validates runtime config
  • opens SQLite
  • connects to Notion
  • wires the bot, scheduler, and parser together
  • starts the long-polling Telegram bot

src/bot.ts

Telegram application layer.

It:

  • polls Telegram updates
  • handles slash commands
  • routes text messages, PDFs, and photos
  • creates approval prompts
  • waits for follow-up text after bare file uploads
  • deletes bot-side approval cards after approval/rejection

src/services/finance.ts

Core business logic.

It:

  • records deals
  • creates revenue rows
  • reserves invoice rows
  • finalizes invoices
  • marks invoices paid
  • builds summaries
  • answers finance questions
  • rebuilds derived client/service summaries

This is the main rules engine of the app.

src/services/parser.ts

Deterministic text parser.

It:

  • parses expense text
  • parses won-deal text
  • parses /invoice_details
  • parses /mark_paid
  • detects backfill dates

src/services/receipt-ocr.ts

Receipt and file interpretation.

It:

  • extracts text from PDFs/images
  • parses structured expense captions
  • merges OCR with explicit caption data
  • creates expense drafts for approval

src/services/invoice-pdf.ts

Local invoice generation logic.

It:

  • chooses the next invoice number
  • prepares invoice render payloads
  • applies invoice branding fields from .env
  • calls the PDF renderer script

scripts/render_invoice_pdf.py

Actual PDF renderer.

It:

  • lays out the invoice page
  • wraps long description text safely
  • positions totals and payment details
  • outputs the final PDF bytes

src/integrations/notion.ts

Notion repository layer.

It:

  • verifies the expected data sources exist
  • writes expenses, deals, revenue, and invoices
  • updates existing rows
  • rebuilds derived Clients and Services

src/integrations/telegram.ts

Telegram Bot API client.

It:

  • sends messages
  • downloads files
  • polls updates
  • deletes bot messages
  • registers the Telegram command menu

src/integrations/codex-cli.ts

Optional AI bridge.

It:

  • runs local codex
  • supports finance Q&A
  • can be disabled

src/storage/database.ts

Local SQLite state store.

It stores:

  • processed Telegram update IDs
  • pending approvals
  • pending attachments
  • scheduler checkpoints
  • invoice override/sequence helpers

Important:

  • this is not your business ledger
  • this is only local runtime state

src/runtime/single-instance.ts

Duplicate-process protection.

It prevents:

  • two polling bots running at once
  • Telegram getUpdates conflicts

src/services/scheduler.ts

Reminder scheduler.

It:

  • checks daily/weekly summary windows
  • sends summaries to the configured Telegram chat
  • uses SQLite checkpoints so summaries do not spam repeatedly

Ledger Structure in Notion

Create one parent page and put these data sources under it:

  • Expense Ledger 2026
  • Deals Pipeline 2026
  • Revenue Ledger 2026
  • Invoices 2026
  • Clients 2026
  • Services 2026
  • Backfill Batches 2026

What Each One Does

Expense Ledger

Source of truth for costs.

Each row should represent one real expense.

Deals Pipeline

Source of truth for commercial work.

Won deals create revenue and reserve invoice numbers.

Revenue Ledger

Tracks booked revenue and collection state.

Invoices

Tracks:

  • reserved
  • draft
  • sent
  • paid
  • cancelled

Clients

Derived summary table.

Used for analysis, not raw operational entry.

Services

Derived service summary table.

Used for service grouping, price observations, and common deliverables.

Backfill Batches

Used to tag historical imports and backfilled records.

Invoice Workflow

Step 1. Log or approve a won deal

Example:

Won deal: [Acme Studio, Spring Launch] [2000] SGD on [March 25th, 2026]. Notes: [1 x Instagram Reel or TikTok Video + 1x IGS repost]

Result:

  • deal row created
  • revenue row created
  • invoice number reserved
  • invoice row created with status reserved

Step 2. Finalize invoice details later

Example:

/invoice_details INV-001 | Acme Studio Pte Ltd | 123 Example Street ; Suite 8 ; Example City | 1 x Instagram Reel or TikTok Video + 1x IGS repost | 2000 | April 20th, 2026 | 30days

Result:

  • existing reserved invoice updated
  • bill-to name/address added
  • PDF generated locally
  • invoice row updated to draft state

Step 3. Mark payment received

Example:

/mark_paid INV-001 2000 2026-04-21

Result:

  • invoice becomes paid
  • revenue row reflects payment

Expense Workflow

Text-only expense

spent 240 on meta ads

Receipt upload with caption

Send a photo or PDF with caption:

Expense: 2026-03-10, Example Electronics, SGD 4242, Editing Workstation (Equipment), paid by card

Receipt upload without caption

If you upload a PDF/image without a caption:

  • bot waits 5 seconds
  • expects a follow-up text message
  • combines the file with the follow-up details
  • errors if nothing arrives

Telegram Commands

Utility

  • /help
  • /whoami
  • /status

Analysis

  • /insights
  • /insights <question>
  • /summary daily
  • /summary weekly
  • /rebuild_insights

Deal and invoice control

  • /approve_deal DEAL_ID
  • /draft_invoice DEAL_ID
  • /invoice_details INVOICE_OR_CLIENT | [BILL_TO_NAME] | [BILLING_ADDRESS_LINE_1 ; LINE_2 ; LINE_3] | DESCRIPTION | AMOUNT | ISSUE_DATE | DUE_DATE
  • /mark_paid INVOICE_ID AMOUNT [YYYY-MM-DD]

Backfill

  • /backfill YYYY-MM-DD <expense or deal text>

Step-by-Step Setup

1. Create the Telegram bot

Open Telegram and message @BotFather.

Run:

/newbot

Then:

  1. choose the bot name
  2. choose the bot username
  3. copy the bot token

Required Telegram settings

In @BotFather:

  1. run /setprivacy
  2. choose your bot
  3. set privacy mode to Disable

Why:

  • with privacy enabled, the bot cannot read normal group messages properly

2. Add the bot to your Telegram group

Add the bot to the shared finance group.

Make sure:

  • it is allowed to send messages
  • it can see group messages

3. Create the Notion integration

In Notion:

  1. create an internal integration
  2. copy the integration token
  3. share your finance workspace page with that integration

4. Create the Notion data sources

Under one parent page, create:

  • Expense Ledger 2026
  • Deals Pipeline 2026
  • Revenue Ledger 2026
  • Invoices 2026
  • Clients 2026
  • Services 2026
  • Backfill Batches 2026

Then collect:

  • parent page ID
  • each data source ID

5. Create your env file

cp .env.example .env

Then fill the real values.

Required values

  • TELEGRAM_BOT_TOKEN
  • TELEGRAM_ALLOWED_CHAT_ID
  • TELEGRAM_NOTIFICATION_CHAT_ID
  • TELEGRAM_ALLOWED_USER_IDS
  • TELEGRAM_APPROVER_USER_IDS
  • NOTION_API_TOKEN
  • NOTION_ROOT_PAGE_ID
  • NOTION_EXPENSES_DATA_SOURCE_ID
  • NOTION_DEALS_DATA_SOURCE_ID
  • NOTION_REVENUE_DATA_SOURCE_ID
  • NOTION_INVOICES_DATA_SOURCE_ID
  • NOTION_CLIENTS_DATA_SOURCE_ID
  • NOTION_SERVICES_DATA_SOURCE_ID
  • NOTION_BACKFILL_BATCHES_DATA_SOURCE_ID

Optional AI values

  • AI_PROVIDER
  • CODEX_CLI_ENABLED
  • CODEX_BIN
  • CODEX_MODEL
  • AI_CONFIRMATION_THRESHOLD

Optional invoice branding values

These are only needed if you want the generated PDF invoice to show your business information cleanly:

  • INVOICE_NUMBER_PREFIX
  • INVOICE_SEQUENCE_START
  • INVOICE_PAYMENT_TERMS_DAYS
  • BUSINESS_NAME
  • BUSINESS_ADDRESS
  • BUSINESS_EMAIL
  • BUSINESS_PHONE
  • PAYMENT_DETAILS

Answer to your earlier question:

  • yes, the BUSINESS_NAME / ADDRESS / EMAIL / PHONE / PAYMENT_DETAILS section is still needed if you want proper invoice PDFs
  • no, it is not needed just to run deal logging or expense logging

6. Verify Codex CLI

codex login status

This is only relevant if you want the optional AI finance-analysis path.

7. Verify Notion connectivity

npm run init:workbook

Expected result:

Notion ledger connectivity verified.

8. Start the bot

npm start

9. Get the real Telegram IDs

In private chat with the bot, send:

/whoami

In the finance group, send:

/whoami

Use those values to fill:

  • TELEGRAM_ALLOWED_CHAT_ID
  • TELEGRAM_NOTIFICATION_CHAT_ID
  • TELEGRAM_ALLOWED_USER_IDS
  • TELEGRAM_APPROVER_USER_IDS

10. Do the first end-to-end test

Test 1: won deal

Won deal: [Acme Studio, Spring Launch] [2000] SGD on [March 25th, 2026]. Notes: [1 x Instagram Reel or TikTok Video + 1x IGS repost]

Approve it.

Test 2: finalize invoice

/invoice_details INV-001 | Acme Studio Pte Ltd | 123 Example Street ; Suite 8 ; Example City | 1 x Instagram Reel or TikTok Video + 1x IGS repost | 2000 | April 20th, 2026 | 30days

Test 3: mark payment

/mark_paid INV-001 2000 2026-04-21

Test 4: receipt expense

Upload a receipt with:

Expense: 2026-03-10, Example Electronics, SGD 4242, Editing Workstation (Equipment), paid by card

Approve it.

Running Commands

npm start
npm run dev
npm run init:workbook
npm run rebuild:insights
npm run summary:daily
npm run summary:weekly
npm test

Always-On Mode

Install the launch agent:

zsh scripts/install-launchd.sh

This gives you:

  • restart on crash
  • survives terminal closure
  • auto-start on login

It does not run while the Mac is asleep.

Why Google Was In The Repo Before

Earlier iterations still carried an optional Google Sheets / Drive path.

That was not your live runtime anymore.

The current repo has been cleaned so the real system is now:

  • Telegram
  • Notion
  • SQLite
  • local PDF invoices
  • optional Codex CLI

No Google integration is required for the current system.

How Another Agent Should Work On This Repo

If you are using Codex, Claude Code, or another coding agent:

Read in this order

  1. src/index.ts
  2. src/bot.ts
  3. src/services/finance.ts
  4. src/integrations/notion.ts
  5. src/storage/database.ts
  6. .env.example

Safe mental model

  • Telegram is input/output
  • FinanceService owns business rules
  • NotionFinanceRepository owns ledger writes
  • LocalStore owns local runtime state
  • InvoiceRenderer owns invoice PDF generation

Safe change rules

  1. do not put secrets or live IDs into committed files
  2. keep bot transport logic in src/bot.ts
  3. keep ledger rules in src/services/finance.ts
  4. keep storage logic in src/integrations/notion.ts and src/storage/database.ts
  5. run npm test

Privacy Rules For This Repo

Safe to commit:

  • source code
  • tests
  • .env.example
  • launchd template
  • scripts
  • README

Do not commit:

  • .env
  • data/
  • logs/
  • other local workspace symlinks
  • generated runtime artifacts

Verification Status

Before the latest push:

  • publish-safety scrub completed
  • repo surface rescanned
  • npm test passed

So the checked-in repo is aligned to the current runtime and does not depend on Google anymore.

About

Local-first Telegram bot for invoices, expenses, revenue tracking, and finance insights with Notion and SQLite.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages