{"id":48533772,"url":"https://github.com/prbento/personal_finance_ai","last_synced_at":"2026-04-27T12:01:35.920Z","repository":{"id":345634828,"uuid":"1186741225","full_name":"prBento/personal_finance_ai","owner":"prBento","description":"LLM-powered personal finance ERP via Telegram. Dual-agent AI pipeline, PostgreSQL AP/AR ledger, FastAPI webhook.","archived":false,"fork":false,"pushed_at":"2026-04-15T22:47:32.000Z","size":342,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-16T00:30:18.584Z","etag":null,"topics":["ai-agents","data-engineering","fastapi","groq","llm","personal-finance","postgresql","python","telegram-bot"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prBento.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-20T00:08:54.000Z","updated_at":"2026-04-15T22:47:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/prBento/personal_finance_ai","commit_stats":null,"previous_names":["prbento/personal_finance_ai"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/prBento/personal_finance_ai","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prBento%2Fpersonal_finance_ai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prBento%2Fpersonal_finance_ai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prBento%2Fpersonal_finance_ai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prBento%2Fpersonal_finance_ai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prBento","download_url":"https://codeload.github.com/prBento/personal_finance_ai/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prBento%2Fpersonal_finance_ai/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32335297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","data-engineering","fastapi","groq","llm","personal-finance","postgresql","python","telegram-bot"],"created_at":"2026-04-08T01:01:37.351Z","updated_at":"2026-04-27T12:01:35.914Z","avatar_url":"https://github.com/prBento.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 💰 Zotto — Finance AI Data App: LLM-Powered Personal ERP\n\n[![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge\u0026logo=python\u0026logoColor=ffdd54)](https://python.org)\n[![PostgreSQL](https://img.shields.io/badge/postgresql-4169e1?style=for-the-badge\u0026logo=postgresql\u0026logoColor=white)](https://postgresql.org)\n[![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge\u0026logo=telegram\u0026logoColor=white)](https://telegram.org)\n[![Railway](https://img.shields.io/badge/Railway-131415?style=for-the-badge\u0026logo=railway\u0026logoColor=white)](https://railway.app)\n[![Groq](https://img.shields.io/badge/Groq-f55036?style=for-the-badge\u0026logo=groq\u0026logoColor=white)](https://groq.com)\n[![FastAPI](https://img.shields.io/badge/FastAPI-005571?style=for-the-badge\u0026logo=fastapi)](https://fastapi.tiangolo.com)\n[![Streamlit](https://img.shields.io/badge/Streamlit-FF4B4B?style=for-the-badge\u0026logo=streamlit\u0026logoColor=white)](https://streamlit.io)\n\n*(Para a versão em Português, [clique aqui](#-versão-em-português-brasileiro))*\n\n## 👨‍💻 Author\n**Bento** — GitHub: [@prBento](https://github.com/prBento)\n\n---\n\n## 🇺🇸 English Version\n\n### 🎯 About the Project\n\n**Zotto** is a Full-Stack Data Application acting as a **personal financial ERP**. It uses Large Language Models to ingest unstructured daily inputs — free-text messages, electronic invoice URLs, and complex PDF bills — and transforms them into a strictly governed relational PostgreSQL database with full Accounts Payable/Receivable tracking, a real-time Cash Flow Statement, and a Streamlit BI dashboard for financial intelligence.\n\n🤝 **AI Collaboration Note:** Product vision, business rules, and architectural decisions by me. Code development through pair-programming with **Gemini AI** (Google) and **Claude** (Anthropic).\n\n---\n\n### 🗺️ System Architecture — Message Flow\n\nEvery message follows a deterministic path from Telegram to the database. Here's how:\n\n```text\n┌─────────────────────────────────────────────────────────────────┐\n│                        TELEGRAM USER                            │\n└──────────┬──────────────────┬──────────────────┬───────────────┘\n           │ Text / URL       │ PDF document      │ /command\n           ▼                  ▼                   ▼\n┌──────────────────────────────────────────────────────────────┐\n│               security_check decorator (ALLOWED_CHAT_IDS)    │\n└──────────┬───────────────────────────────────┬───────────────┘\n           │ ingestion                         │ /contas /extrato /help\n           ▼                                   ▼\n┌───────────────────────┐            ┌──────────────────────┐\n│  PostgreSQL           │            │  Command handlers    │\n│  process_queue        │            │  (direct DB reads)   │\n│  status=PENDING       │            └──────────────────────┘\n└──────────┬────────────┘\n           │ every 10s\n           ▼\n┌───────────────────────────────┐\n│   queue_processor (worker)    │  ← rate limit? reschedule with backoff\n└──────┬─────────────┬──────────┘\n       │ URL         │ PDF / text\n       ▼             ▼\n┌──────────┐  ┌────────────┐\n│BeautifulS│  │PyPDF text  │\n│oup scrape│  │extraction  │\n└──────┬───┘  └──────┬─────┘\n       └──────┬───────┘\n              ▼\n┌─────────────────────────┐     ┌──────────────────────────┐\n│  Agent 1 — Extract      │────▶│  Agent 2 — Enrich        │\n│  temp=0.0               │     │  temp=0.1                │\n│  CoT date reasoning     │     │  disambiguation rules    │\n└─────────────────────────┘     └──────────┬───────────────┘\n                                            │\n                                            ▼\n                               ┌────────────────────────┐\n                               │  Math validation       │\n                               │  discount detector     │\n                               │  duplicate check       │\n                               └──────────┬─────────────┘\n                                          │\n                                          ▼\n                          ┌───────────────────────────────┐\n                          │  State Machine                │\n                          │  → ask method / location      │◀─── user replies\n                          │  → ask card / first date      │\n                          │  → show summary (Sim/Não)     │\n                          └──────────────┬────────────────┘\n                                         │ confirmed\n                                         ▼\n                          ┌───────────────────────────────┐\n                          │  PostgreSQL                   │\n                          │  transactions                 │◀──── Streamlit\n                          │  transaction_items            │      dashboard.py\n                          │  installments                 │      reads here\n                          └───────────────────────────────┘\n```\n\n**Deployment modes:**\n- `prod` → FastAPI + Uvicorn → Telegram pushes to `POST /webhook`\n- `dev` → `run_polling()` → bot asks Telegram every few seconds\n- `dashboard` → Streamlit service on Railway, same PostgreSQL plugin\n\n---\n\n### 🌟 Key Features\n\n- **Multimodal Ingestion:** Free-text, NFC-e URLs, and PDF utility bills in one pipeline.\n- **Dual-Agent AI:** Agent 1 extracts (`temp=0.0`); Agent 2 categorizes (`temp=0.1`). Disambiguation ruleset prevents common misclassifications (Total Pass → Academy, iFood → Food, streaming → Subscriptions, NF-e → always Expense).\n- **Hidden Discount Detection:** If `sum(items) \u003e invoice_total`, the difference is automatically registered as a discount.\n- **Resilient Outbox Queue:** Exponential Backoff (60s–3600s), TPD-aware 90-minute deferral, `max_attempts` dead-item protection, busy-state deferral without consuming retry attempts.\n- **AP/AR Dashboard (`/contas`):** Accordion credit card grouping, income vs expense differentiation, smart anticipation logic, dynamic method override, overdue alerts, Fast-Forward, Isolated View.\n- **Cash Flow Statement (`/extrato`):** Saldo Atual + Projetado, Benefit Wallet isolation (VA/VR), dynamic installment index (`8/10`), `[B]` tag, `*` for pending items.\n- **Streamlit BI Dashboard (`dashboard.py`):**\n  - **Saúde do Mês** — KPIs with savings rate, correct cash-basis values (`paid_amount` for PAID, `expected_amount` for PENDING), benefit wallet isolation.\n  - **Tendências** — Monthly income/expense series, savings rate evolution, category trends (multi-select), card participation breakdown, accumulated discount savings.\n  - **Cartões \u0026 Parcelas** — Income commitment gauge (adjustable horizon), debt curve (burn rate), active installment drill-down.\n  - **Projeção de Caixa** — Projected monthly + cumulative balance, tabular summary.\n  - **Operacional — Itens** — Hierarchical treemap (macro → category → subcategory), sunburst drill-down, top items \u0026 brands, frequency vs ticket scatter, day-of-month heatmap, full audit table with triple filters.\n- **Cash Basis Accounting:** Paid installment `month` updates to payment month. `/extrato` and Streamlit reflect when money moved.\n- **Cloud-Native:** Two Railway services sharing one PostgreSQL plugin.\n\n---\n\n### 🛠️ Tech Stack\n\n| Layer | Technology | Version |\n|-------|-----------|---------|\n| Language | Python | 3.12 |\n| Conversational Interface | `python-telegram-bot` | 20.8 |\n| Web Server (prod) | FastAPI + Uvicorn | 0.135.3 / 0.44.0 |\n| AI Engine | Groq API (`llama-4-scout-17b`) | — |\n| Database | PostgreSQL (Docker / Railway) | 15 |\n| DB Driver | `psycopg2-binary` | 2.9.11 |\n| BI Dashboard | Streamlit + Plotly | — |\n| Web Scraping | `BeautifulSoup4` | 4.14.3 |\n| PDF Extraction | `PyPDF` | 6.9.1 |\n| Date Arithmetic | `python-dateutil` | 2.9.0 |\n\n---\n\n### 🤖 Creating your Telegram Bot\n\n1. Open Telegram → search `@BotFather` → `/newbot` → copy the **HTTP API Token**.\n2. Send any message to your new bot, then talk to `@userinfobot` to find your personal `chat_id` for `ALLOWED_CHAT_IDS`.\n\n---\n\n### 🚀 How to Run Locally\n\n**Prerequisites:** Python 3.12, Docker, Groq API key ([console.groq.com](https://console.groq.com)).\n\n1. **Clone:** `git clone https://github.com/prBento/personal_finance_ai.git \u0026\u0026 cd personal_finance_ai`\n\n2. **Create `.env`** (never commit):\n   ```env\n   ENVIRONMENT=dev\n   TELEGRAM_TOKEN_DEV=your_dev_bot_token\n   TELEGRAM_TOKEN_PROD=your_prod_bot_token\n   GROQ_API_KEY_DEV=your_dev_groq_key\n   GROQ_API_KEY_PROD=your_prod_groq_key\n   DB_USER=your_db_user\n   DB_PASSWORD=your_db_password\n   DB_NAME=db_finance\n   DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@localhost:5432/${DB_NAME}\n   ALLOWED_CHAT_IDS=your_telegram_chat_id\n   RAILWAY_DB_URL=postgresql://postgres:password@host:5432/railway\n   ```\n\n3. **Start DB:** `docker-compose up -d`\n\n4. **Run bot:** `python -m venv venv \u0026\u0026 source venv/bin/activate \u0026\u0026 pip install -r requirements.txt \u0026\u0026 python bot.py`\n\n5. **Run dashboard (separate terminal):** `streamlit run dashboard.py`\n\n6. **Sync Production Data to Local (Optional):** To test the dashboard locally with real data, use the sync script. It securely consumes credentials from your `.env` file. Ensure you have `RAILWAY_DB_URL` added to your `.env`, then run in PowerShell:\n   ```powershell\n   .\\sync_db.ps1\n   ```\n   *This script creates a disposable container that downloads production data and injects it directly into your local database in memory, without creating files and preserving UTF-8 formatting.*\n\n7. **Test Telegram Mini App Locally (Optional):** To test the `/dash` command locally, you must expose your Streamlit port securely. Download **ngrok**, run `.\\ngrok http 0000`, copy the generated `https://...ngrok-free.app` URL, and set it as `DASHBOARD_URL` in your `.env`.\n\n---\n\n### ☁️ Cloud Deployment (Railway)\n\nThe project runs as **two independent Railway services** sharing a single PostgreSQL plugin.\n\n#### Service 1 — Bot (FastAPI + Webhook)\n\n1. Create a Railway project → add **PostgreSQL** plugin.\n2. Connect your GitHub repo. Railway detects `.python-version` (Python 3.12) and installs `requirements.txt` automatically.\n3. In the service **Variables** tab, add:\n   - `ENVIRONMENT=prod`\n   - `TELEGRAM_TOKEN_PROD`, `GROQ_API_KEY_PROD`\n   - `DATABASE_URL` (use Railway's **internal** URL from the PostgreSQL plugin)\n   - `ALLOWED_CHAT_IDS`\n4. Ensure the `Procfile` reads `web: python bot.py` (not `worker`) so Railway assigns a public URL and the `PORT` variable for the webhook server.\n5. After deploy, register the webhook with Telegram:\n   ```\n   [https://api.telegram.org/bot](https://api.telegram.org/bot)\u003cTOKEN\u003e/setWebhook?url=https://\u003cyour-bot-service-url\u003e/webhook\n   ```\n\n#### Service 2 — Dashboard (Streamlit)\n\n1. In the **same Railway project**, click **+ New Service → GitHub Repo** and connect the same repository again (Railway allows multiple services per repo).\n2. In the new service's **Settings → Start Command**, set:\n   ```\n   streamlit run dashboard.py --server.port $PORT --server.address 0.0.0.0\n   ```\n3. In the service **Variables** tab, add only:\n   - `DATABASE_URL` (same internal URL from the PostgreSQL plugin — both services share it)\n4. Optionally set a custom domain or use the Railway-generated URL to access the dashboard.\n5. The dashboard connects directly to the same PostgreSQL instance the bot writes to — no extra configuration needed.\n\n---\n\n### 🗂️ Project Structure\n\n```text\npersonal_finance_ai/\n├── bot.py              # Handlers, State Machine, queue worker, AI pipeline, FastAPI server\n├── database.py         # All DB functions, connection pool, CTE queries, table creation\n├── dashboard.py        # Streamlit BI dashboard (5 analytical tabs)\n├── prompts.py          # AI Prompts (Extraction \u0026 Enrichment)\n├── Procfile            # Railway bot service: \"web: python bot.py\"\n├── docker-compose.yml  # Local PostgreSQL\n├── requirements.txt    # Python dependencies (includes streamlit, plotly)\n├── sync_db.ps1         # PowerShell script to sync production DB to local DB\n├── .python-version     # Forces Python 3.12 on Railway Nixpacks\n├── ARCHITECTURE.md     # Full technical specification\n├── BACKLOG.md          # Product backlog and roadmap\n└── .env                # Secrets (git-ignored)\n```\n\n---\n\n### 🚦 Conventional Commits\n\n| Prefix | Use for |\n|--------|---------|\n| `feat:` | New feature | `fix:` | Bug fix |\n| `refactor:` | No behavior change | `docs:` | Documentation |\n| `chore:` | Build or config | | |\n\n---\n\n### 🗺️ Development Roadmap\n\n#### ✅ V1 — Production Foundation\nCore ingestion, Outbox + Backoff, NFC-e + PDF, installment engine, connection pool, whitelist, DATE columns.\n\n#### ✅ V2 — Accounting Engine \u0026 UX\n- Accordion AP/AR dashboard with group invoice payment.\n- `/extrato` with cash-basis accounting, benefit wallet, installment index (`8/10`).\n- Dynamic payment method override at settlement time.\n- Credit card anticipation (moves installment to next invoice cycle, stays PENDING).\n- FastAPI webhook architecture. Interactive `/help` menu.\n- Hidden discount detector. Disambiguation ruleset.\n\n#### ✅ V3 — Scale \u0026 Visualization\n- Streamlit BI dashboard on Railway (second service, shared PostgreSQL).\n- 5-tab analytical dashboard: Saúde do Mês, Tendências, Cartões \u0026 Parcelas, Projeção de Caixa, Operacional.\n- Correct cash-basis KPIs (`paid_amount` for PAID), savings rate metric.\n- Benefit wallet isolation in Streamlit (same logic as `/extrato`).\n- Hierarchical item analysis: treemap, sunburst, frequency×ticket scatter, day heatmap.\n- Accumulated discount/anticipation savings curve.\n- Income commitment gauge with adjustable horizon slider.\n- Blacklist filter for locations (starts empty, select items to exclude).\n- Extract prompts to `prompts.py`.\n\n#### 🚧 V4 — Hardening \u0026 Intelligence\n- [ ] Replace `print()` with `logging` module for structured log levels.\n- [ ] Multi-transaction support per LLM response.\n- [ ] PDF password decryption mid-conversation.\n- [ ] Replace `psycopg2` with `asyncpg` (non-blocking DB calls in FastAPI event loop).\n- [ ] Budget targets per category (stored in DB, configurable via dashboard).\n\n---\n---\n\n## 🇧🇷 Versão em Português Brasileiro\n\n### 🎯 Sobre o Projeto\n\n**Zotto** é uma Aplicação de Dados Full-Stack que atua como um **ERP financeiro pessoal**. Usa LLMs para ingerir inputs não estruturados do dia a dia — mensagens de texto livre, URLs de notas fiscais (NFC-e) e PDFs complexos de contas — e os transforma em um banco de dados PostgreSQL rigidamente governado. O projeto rastreia Contas a Pagar/Receber, gera um Extrato de Fluxo de Caixa em tempo real e fornece um Dashboard BI no Streamlit para inteligência financeira.\n\n🤝 **Colaboração IA:** Decisões de produto, regras de negócio e arquitetura por mim. Código desenvolvido em pair-programming com **Gemini AI** (Google) e **Claude** (Anthropic).\n\n---\n\n### 🗺️ Arquitetura do Sistema — Fluxo de Mensagens\n\nToda mensagem segue um caminho determinístico do Telegram até o banco de dados. Veja como funciona:\n\n```text\n┌─────────────────────────────────────────────────────────────────┐\n│                        USUÁRIO TELEGRAM                         │\n└──────────┬──────────────────┬──────────────────┬───────────────┘\n           │ Texto / URL      │ Documento PDF    │ /comandos\n           ▼                  ▼                  ▼\n┌──────────────────────────────────────────────────────────────┐\n│       Decorator security_check (ALLOWED_CHAT_IDS)            │\n└──────────┬───────────────────────────────────┬───────────────┘\n           │ Ingestão                          │ /contas /extrato /help\n           ▼                                   ▼\n┌───────────────────────┐            ┌──────────────────────┐\n│  PostgreSQL           │            │  Handlers de comando │\n│  process_queue        │            │  (leitura direta BD) │\n│  status=PENDING       │            └──────────────────────┘\n└──────────┬────────────┘\n           │ a cada 10s\n           ▼\n┌───────────────────────────────┐\n│   queue_processor (worker)    │  ← rate limit? reagenda com backoff\n└──────┬─────────────┬──────────┘\n       │ URL         │ PDF / texto\n       ▼             ▼\n┌──────────┐  ┌────────────┐\n│Scrape via│  │Extração de │\n│BeautifulS│  │texto PyPDF │\n└──────┬───┘  └──────┬─────┘\n       └──────┬───────┘\n              ▼\n┌─────────────────────────┐     ┌──────────────────────────┐\n│  Agente 1 — Extração    │────▶│  Agente 2 — Enriquec.    │\n│  temp=0.0               │     │  temp=0.1                │\n│  CoT datas              │     │  regras desambiguação    │\n└─────────────────────────┘     └──────────┬───────────────┘\n                                            │\n                                            ▼\n                               ┌────────────────────────┐\n                               │  Validação matemática  │\n                               │  detector de desconto  │\n                               │  verificação duplicata │\n                               └──────────┬─────────────┘\n                                          │\n                                          ▼\n                          ┌───────────────────────────────┐\n                          │  Máquina de Estados           │\n                          │  → pede método / local        │◀─── usuário responde\n                          │  → pede cartão / 1ª data      │\n                          │  → mostra resumo (Sim/Não)    │\n                          └──────────────┬────────────────┘\n                                         │ confirmado\n                                         ▼\n                          ┌───────────────────────────────┐\n                          │  PostgreSQL                   │\n                          │  transactions                 │◀──── Streamlit\n                          │  transaction_items            │      dashboard.py\n                          │  installments                 │      lê aqui\n                          └───────────────────────────────┘\n```\n\n**Modos de Deploy:**\n- `prod` → FastAPI + Uvicorn → Telegram envia via `POST /webhook`\n- `dev` → `run_polling()` → bot pesquisa ativamente no Telegram\n- `dashboard` → Serviço Streamlit no Railway, usando o mesmo plugin PostgreSQL\n\n---\n\n### 🌟 Funcionalidades Principais\n\n- **Ingestão Multimodal:** Texto livre, URLs de NFC-e e faturas em PDF em um único pipeline.\n- **IA de Duplo Agente:** Agente 1 extrai dados (`temp=0.0`); Agente 2 categoriza (`temp=0.1`). Regras de desambiguação evitam erros comuns (ex: Total Pass → Academia, iFood → Alimentação, NF-e → sempre Despesa).\n- **Detecção de Desconto Oculto:** Se a `soma(itens) \u003e total_nota`, a diferença é automaticamente registrada como desconto aplicado.\n- **Fila Outbox Resiliente:** Backoff Exponencial (60s–3600s), adiamento de 90 min para limite TPD, proteção contra limite de tentativas (`max_attempts`), pausa de fila sem consumir tentativas se o usuário estiver respondendo.\n- **Dashboard AP/AR (`/contas`):** Agrupamento por cartão em acordeon, diferenciação de receitas/despesas, lógica de antecipação, mudança de método de pagamento na hora da baixa, alertas de vencimento, avanço rápido e Visão Isolada.\n- **Extrato Financeiro (`/extrato`):** Saldo Atual vs Projetado, isolamento da Carteira de Benefícios (VA/VR), índice dinâmico de parcelas (`8/10`), tag `[B]`, e `*` para lançamentos previstos.\n- **Dashboard BI Streamlit (`dashboard.py`):**\n  - **Saúde do Mês** — KPIs com taxa de poupança, valores corretos em regime de caixa (`paid_amount` para PAGO, `expected_amount` para PENDENTE), isolamento de benefícios.\n  - **Tendências** — Série mensal de receitas/despesas, evolução da poupança, tendências por categoria (multi-select), participação por cartão e economia acumulada.\n  - **Cartões \u0026 Parcelas** — Gauge de comprometimento de renda (horizonte ajustável), curva de dívida (burn rate) e detalhamento de parcelamentos ativos.\n  - **Projeção de Caixa** — Saldo projetado mensal + acumulado e resumo em tabela.\n  - **Operacional (Itens)** — Treemap hierárquico (macro → categoria → subcategoria), sunburst, top itens e marcas, scatter de frequência vs ticket, heatmap por dia do mês e tabela de auditoria com filtros triplos.\n- **Contabilidade em Regime de Caixa:** O `mês` da parcela se ajusta ao mês de pagamento real. O `/extrato` e o Streamlit refletem a movimentação exata do dinheiro.\n- **Cloud-Native:** Dois serviços no Railway compartilhando um único plugin PostgreSQL.\n\n---\n\n### 🛠️ Stack Tecnológico\n\n| Camada | Tecnologia | Versão |\n|--------|-----------|--------|\n| Linguagem | Python | 3.12 |\n| Interface Bot | `python-telegram-bot` | 20.8 |\n| Servidor Web (prod) | FastAPI + Uvicorn | 0.135.3 / 0.44.0 |\n| Motor IA | Groq API (`llama-4-scout-17b`) | — |\n| Banco de Dados | PostgreSQL (Docker / Railway) | 15 |\n| Driver BD | `psycopg2-binary` | 2.9.11 |\n| Dashboard BI | Streamlit + Plotly | — |\n| Web Scraping | `BeautifulSoup4` | 4.14.3 |\n| Leitura PDF | `PyPDF` | 6.9.1 |\n| Aritmética de Datas | `python-dateutil` | 2.9.0 |\n\n---\n\n### 🤖 Criando seu Bot no Telegram\n\n1. Abra o Telegram → busque por `@BotFather` → digite `/newbot` → copie o **Token da API HTTP**.\n2. Envie qualquer mensagem para o seu novo bot, e em seguida converse com o `@userinfobot` para descobrir o seu `chat_id` pessoal. Insira esse número no seu `ALLOWED_CHAT_IDS`.\n\n---\n\n### 🚀 Como Rodar Localmente\n\n**Pré-requisitos:** Python 3.12, Docker, Chave de API do Groq ([console.groq.com](https://console.groq.com)).\n\n1. **Clonar:** `git clone https://github.com/prBento/personal_finance_ai.git \u0026\u0026 cd personal_finance_ai`\n\n2. **Criar `.env`** (nunca faça commit):\n   ```env\n   ENVIRONMENT=dev\n   TELEGRAM_TOKEN_DEV=seu_token_dev\n   TELEGRAM_TOKEN_PROD=seu_token_prod\n   GROQ_API_KEY_DEV=sua_chave_groq_dev\n   GROQ_API_KEY_PROD=sua_chave_groq_prod\n   DB_USER=seu_usuario_bd\n   DB_PASSWORD=sua_senha_bd\n   DB_NAME=db_finance\n   DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@localhost:5432/${DB_NAME}\n   ALLOWED_CHAT_IDS=seu_chat_id_telegram\n   RAILWAY_DB_URL=postgresql://postgres:senha@host:5432/railway\n   ```\n\n3. **Subir BD Local:** `docker-compose up -d`\n\n4. **Rodar bot:** `python -m venv venv \u0026\u0026 source venv/bin/activate \u0026\u0026 pip install -r requirements.txt \u0026\u0026 python bot.py`\n\n5. **Rodar dashboard (em outro terminal):** `streamlit run dashboard.py`\n\n6. **Sincronizar Banco de Produção (Opcional):** Para testar o painel localmente com dados reais, utilize o script de sincronização. Ele consome as credenciais do seu arquivo `.env` de forma segura. Certifique-se de ter adicionado a variável `RAILWAY_DB_URL` no seu `.env` e rode no PowerShell:\n   ```powershell\n   .\\sync_db.ps1\n   ```\n   *O script gera um container descartável que baixa os dados de produção e os injeta diretamente no seu banco local em memória, sem gerar arquivos e preservando o formato UTF-8.*\n\n7. **Testar Web App Localmente (Opcional):** Para testar o comando `/dash`, os Mini Apps do Telegram exigem uma URL HTTPS segura. Baixe o **ngrok**, exponha a porta do Streamlit rodando `.\\ngrok http 0000`, copie a URL gerada e adicione como `DASHBOARD_URL` no seu `.env`.\n\n---\n\n### ☁️ Deploy na Nuvem (Railway)\n\nO projeto roda como **dois serviços independentes** no mesmo projeto Railway, compartilhando um único plugin PostgreSQL.\n\n#### Serviço 1 — Bot (FastAPI + Webhook)\n\n1. Crie um projeto no Railway → adicione o plugin **PostgreSQL**.\n2. Conecte o repositório GitHub. O Railway detecta o `.python-version` (Python 3.12) e instala o `requirements.txt` automaticamente.\n3. Na aba **Variables** do serviço, adicione:\n   - `ENVIRONMENT=prod`\n   - `TELEGRAM_TOKEN_PROD`, `GROQ_API_KEY_PROD`\n   - `DATABASE_URL` (URL **interna** do plugin PostgreSQL do Railway)\n   - `ALLOWED_CHAT_IDS`\n4. Garanta que o arquivo `Procfile` contenha `web: python bot.py` para o Railway provisionar a URL pública e a variável `PORT` para o servidor webhook.\n5. Após o deploy, registre o webhook enviando este link no seu navegador:\n   ```\n   [https://api.telegram.org/bot](https://api.telegram.org/bot)\u003cTOKEN\u003e/setWebhook?url=https://\u003curl-do-seu-servico\u003e/webhook\n   ```\n\n#### Serviço 2 — Dashboard (Streamlit)\n\n1. No **mesmo projeto Railway**, clique em **+ New Service → GitHub Repo** e conecte o mesmo repositório novamente (o Railway permite múltiplos serviços para o mesmo repositório).\n2. Na aba **Settings → Start Command** do novo serviço, defina:\n   ```\n   streamlit run dashboard.py --server.port $PORT --server.address 0.0.0.0\n   ```\n3. Na aba **Variables** deste serviço, adicione apenas:\n   - `DATABASE_URL` (a mesma URL interna do plugin PostgreSQL — os dois serviços a compartilham)\n4. Defina um domínio customizado ou use a URL gerada pelo Railway para acessar o dashboard.\n5. O dashboard se conecta diretamente à mesma instância PostgreSQL onde o bot escreve os dados.\n\n---\n\n### 🗂️ Estrutura do Projeto\n\n```text\npersonal_finance_ai/\n├── bot.py              # Handlers, Máquina de Estados, worker de fila, IA e servidor FastAPI\n├── database.py         # Funções de BD, connection pool, queries complexas e criação de tabelas\n├── dashboard.py        # Dashboard BI no Streamlit (5 abas analíticas)\n├── prompts.py          # Prompts da IA (Extração e Enriquecimento)\n├── Procfile            # Serviço bot do Railway: \"web: python bot.py\"\n├── docker-compose.yml  # Banco PostgreSQL local\n├── requirements.txt    # Dependências (inclui streamlit, plotly, fastapi)\n├── sync_db.ps1         # Script PowerShell para clonar a base de prod para o ambiente local\n├── .python-version     # Força o Python 3.12 no Nixpacks do Railway\n├── ARCHITECTURE.md     # Especificação técnica completa do projeto\n├── BACKLOG.md          # Backlog de produto e roadmap\n└── .env                # Variáveis secretas (ignorado pelo git)\n```\n\n---\n\n### 🚦 Commits Convencionais\n\n| Prefixo | Uso |\n|---------|---------|\n| `feat:` | Nova funcionalidade | `fix:` | Correção de bug |\n| `refactor:` | Mudança sem impacto visual/funcional | `docs:` | Documentação |\n| `chore:` | Build, pacotes ou configuração | | |\n\n---\n\n### 🗺️ Roadmap de Desenvolvimento\n\n#### ✅ V1 — Fundação de Produção\nIngestão central, Outbox + Backoff, NFC-e + PDF, motor de parcelamento, connection pool, whitelist de segurança, colunas em formato DATE.\n\n#### ✅ V2 — Motor Contábil e UX\n- Dashboard AP/AR com menu acordeon e pagamento em massa de faturas.\n- `/extrato` rodando 100% em regime de caixa, com carteira benefício isolada e índice de parcelas (`8/10`).\n- Sobrescrita de método de pagamento no momento da baixa.\n- Antecipação de cartão de crédito (move a parcela para o fechamento da fatura seguinte, mas mantém PENDENTE).\n- Arquitetura FastAPI webhook. Menu `/help` interativo.\n- Detecção algorítmica de desconto oculto. Regras de desambiguação de IA.\n\n#### ✅ V3 — Escala e Visualização\n- Dashboard Streamlit BI no Railway (segundo serviço, mesmo PostgreSQL).\n- 5 abas analíticas: Saúde do Mês, Tendências, Cartões \u0026 Parcelas, Projeção de Caixa, Operacional.\n- KPIs em regime de caixa absoluto (`paid_amount` vs `expected_amount`) e métrica de taxa de poupança.\n- Isolamento da carteira de benefício no Streamlit (mesma lógica do `/extrato`).\n- Análise de itens (regime de competência): treemap hierárquico, sunburst, frequência vs ticket, heatmap de dias.\n- Gráfico de curva de descontos acumulados e antecipações.\n- Gauge de comprometimento de renda com slider de horizonte futuro.\n- Filtro de locais em formato Blacklist (inicia vazio, ocultando apenas os itens selecionados).\n- Refatoração dos prompts para o arquivo central `prompts.py`.\n\n#### 🚧 V4 — Hardening e Inteligência\n- [ ] Substituir `print()` pelo módulo `logging` com níveis estruturados.\n- [ ] Suporte a multi-transação (várias compras na mesma resposta do LLM).\n- [ ] Quebra de senha de PDFs de operadoras de celular durante a conversa.\n- [ ] Substituir `psycopg2` por `asyncpg` (chamadas não-bloqueantes no event loop do FastAPI).\n- [ ] Metas de orçamento por categoria (armazenadas no banco e geridas pelo painel).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprbento%2Fpersonal_finance_ai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprbento%2Fpersonal_finance_ai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprbento%2Fpersonal_finance_ai/lists"}