Oracle3
Open-source trading engine and MCP server for prediction markets. Fee-aware no-arbitrage trading across related contracts, live on Kalshi, Polymarket and Solana or on paper.
Manage grant budgets and financial reports for NGOs and donors
AI summary · README
FinancePython · TypeScriptGitHub @arutshOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
arutsh/GrantFlow
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
GrantFlow is an open-source platform for budget management and financial reporting in NGOs and donor organizations. It was born from 20 years of watching organizations manage grant budgets in incompatible Excel files — and a belief that modern software engineering can fix that.
Status: Active development — live in production.
→ Product Overview — what GrantFlow does, who it's for, and why it exists.Read the full README ↗Version: 0.1.0 · Last updated: 2026-09-15
GrantFlow is an open-source platform for budget management and financial reporting in NGOs and donor organizations. It was born from 20 years of watching organizations manage grant budgets in incompatible Excel files — and a belief that modern software engineering can fix that.
Status: Active development — live in production.
→ Product Overview — what GrantFlow does, who it's for, and why it exists.
graph TB
FE["Frontend\nReact 19 + Vite\n:5173 (dev)"]
GW["Nginx Gateway\n:8082"]
FE -->|HTTP| GW
GW -->|/api/v1/users, /auth,\n/register, /customers, …| US
GW -->|/api/v1/budgets, /budget-lines,\n/reports, /attachments, …| BS
GW -->|/api/v1/ai| AI
GW -->|/api/v1/chat\nSSE streaming| CH
subgraph Services
US["users-service\nFastAPI :8000"]
BS["budget-service\nFastAPI :8001"]
AI["ai-service\nFastAPI :8002\n(stateless reasoning)"]
CH["chat-service\nFastAPI :8003\n(agent host)"]
WK["worker\nCelery"]
end
CH -->|POST /ai/decide\nplain JSON| AI
CH -->|REST\ntool dispatch| BS
subgraph Data
PG[("PostgreSQL :5432\ngrandflow_users\ngrandflow_budget\ngrandflow_ai\ngrandflow_chat")]
RD[("Redis :6379\nSessions · Rate limits")]
RMQ[("RabbitMQ :5672\nEvent broker / Celery transport")]
end
subgraph Observability
OC["OTEL Collector\n:4317"]
JG["Jaeger\n:16686"]
PM["Prometheus\n:9090"]
GF["Grafana\n:3002"]
end
US --> PG
BS --> PG
AI --> PG
CH --> PG
AI --> RD
US --> RMQ
BS -->|consumes events| RMQ
WK -->|broker| RMQ
WK -->|result backend| RD
US -->|OTLP| OC
BS -->|OTLP| OC
AI -->|OTLP| OC
CH -->|OTLP| OC
OC --> JG
OC --> PM
PM --> GF
Communication patterns:
:8082), including a direct route to ai-service (/api/v1/ai/*) for account-level settings/model catalog, separate from chat-service's own decision-request pathPOST /ai/decide) via shared/ai_clientfrontend → chat, chat → ai, chat → domain REST. No ai → domain, no domain → domain, no domain → ai — ai carries zero domain knowledge and every domain service can, in principle, be rewritten in another stack independently.| Layer | Technology |
|---|---|
| Backend | Python 3.11+ · FastAPI 0.116 · Pydantic v2 |
| Frontend | React 19 · TypeScript 5.8 · Vite · TailwindCSS · TanStack Query |
| ORM | SQLAlchemy 2.0 (async) · Alembic migrations |
| Database | PostgreSQL 15 (one DB per service) |
| Cache | Redis 7 |
| Messaging | RabbitMQ 3 (aio-pika) |
| Auth | JWT (HS256) · refresh token rotation via Redis |
| AI | Anthropic API (BYOK) · Ollama (local dev) · pydantic-ai |
| MailerSend · Mailjet (transactional, dual-provider) | |
| Observability | OpenTelemetry (OTLP) · Jaeger/Prometheus/Grafana (dev) · Grafana Cloud (prod) |
| Gateway | Nginx |
| Containerization | Docker · Docker Compose |
| CI | GitHub Actions (lint + tests per service) |
:8000User and customer management, JWT authentication, role-based access control. Publishes user.created / user.updated events to RabbitMQ. Customers are modelled with is_ngo and is_donor boolean flags to support both sides of a grant relationship.
:8001Budget and budget-line CRUD. Consumes user events from RabbitMQ to maintain a local read model. Carries zero AI/chat knowledge — the parse-to-budget flow is driven by chat-service against this service's public REST API. Key endpoints:
POST /api/v1/budgets/with-lines — atomic create: budget + all lines in one transaction:8002Pure stateless reasoning — no domain knowledge, no outbound calls to other services. POST /ai/decide takes a message, conversation history, tool JSON schemas, and domain context, and returns either a tool-call decision or a reply. Features:
:8003Agent host — owns conversations and messages server-side (any-device chat history), the tool registry, and the dispatch loop. Serves POST /chat/stream (SSE) to the frontend and calls ai-service's /ai/decide for reasoning via shared/ai_client. Features:
list_tools() / call_tool()): the budget toolset is generated by an in-process FastMCP from_openapi bridge over budget's OpenAPI spec (mcp_bridge.py), with route maps and a dispatch bridge for server-injected resource idsbudget_id) are injected server-side from the URL context, never supplied by the modelBackground jobs shared across services — RabbitMQ as broker, Redis as result backend, per-domain queues (ai, budget, users). Runs a daily scheduled cleanup of expired AI sessions, plus on-demand tasks: verification/invite/password-reset email delivery and feedback notifications.
| Decision | Rationale |
|---|---|
| One PostgreSQL DB per service | Enforces service boundaries; avoids shared-schema coupling |
Shared Python library (/shared) | Common JWT logic, Pydantic schemas, OpenTelemetry setup, and the ai_client decision-request library without duplication |
| RabbitMQ over direct HTTP for user events | Decouples budget-service from users-service availability |
| OpenTelemetry (OTLP) over Sentry | Vendor-agnostic; same instrumentation works with Jaeger today, any backend tomorrow |
| FastAPI async-first | All I/O (DB, Redis, HTTP, RabbitMQ) runs async; no sync blocking in the hot path |
| Nginx as single gateway | One CORS policy, one entry point; services are not directly exposed |
| Dedicated chat-service (agent host) over client-held history or ai-owned threads | Any-device chat history needs a server; keeps ai-service stateless and domain services free of chat plumbing |
ai-service is pure stateless reasoning (/ai/decide), no outbound calls | Keeps the dependency DAG acyclic (frontend → chat → {ai, domain REST}); domain services stay swappable for another stack independently |
| Tool registry is MCP-shaped from day one | Same consumer-facing interface for hand-curated and OpenAPI→MCP-bridged tools; budget's registry now runs entirely on the OpenAPI→MCP bridge |
All services export traces and metrics via OTLP to the OpenTelemetry Collector, which fans out to Jaeger (traces) and Prometheus (metrics). Grafana sits on top of Prometheus for dashboards.
Auto-instrumented via shared/observability/__init__.py:
| Tool | URL | Purpose |
|---|---|---|
| Jaeger | http://localhost:16686 | Distributed traces, latency, error rates |
| Prometheus | http://localhost:9090 | Metrics queries and scrape targets |
| Grafana | http://localhost:3002 | Dashboards (admin / admin) |
| RabbitMQ UI | http://localhost:15672 | Queue inspection, message rates |
For more detail see monitoring/README.md.
Two modes are available depending on the use case:
| Dev mode | Local mode | |
|---|---|---|
| Use case | Active development | Demo, testing, non-technical users |
| Services | Run on host (hot reload) | Run in Docker (no local deps needed) |
| Entry point | ./dev.sh | ./local.sh |
| Frontend | http://localhost:5173 | http://localhost:4000 |
| Nginx gateway | http://localhost:8082 | http://localhost:9082 |
Prerequisites: Docker, Python 3.11+, Node.js 18+
Infrastructure runs in Docker; services run on the host for hot reload.
# 1. Start infrastructure (PostgreSQL, Redis, RabbitMQ, Nginx, observability)
./dev.sh up
# 2. Start each service in its own terminal
cd services/users && alembic upgrade head && python -m uvicorn main:app --reload --port 8000
cd services/budget && alembic upgrade head && python -m uvicorn main:app --reload --port 8001
cd services/ai && alembic upgrade head && python -m uvicorn main:app --reload --port 8002
cd services/chat && alembic upgrade head && python -m uvicorn main:app --reload --port 8003
# 3. Start the frontend
cd frontend-typescript && npm install && npm run dev
Dev mode endpoints:
| URL | |
|---|---|
| Frontend | http://localhost:5173 |
| Nginx gateway | http://localhost:8082 |
| Users API docs | http://localhost:8000/docs |
| Budget API docs | http://localhost:8001/docs |
| AI API docs | http://localhost:8002/docs |
| Chat API docs | http://localhost:8003/docs |
VSCode debugging — each service exposes debugpy (enable with VSCODE_DEBUGGER=1):
| Service | debugpy port |
|---|---|
| users-service | 5678 |
| budget-service | 5680 |
| ai-service | 5682 |
| chat-service | 5684 |
Attach from VS Code with "remoteRoot": "/app".
Other dev.sh commands:
./dev.sh down # Stop infrastructure
./dev.sh logs # Stream container logs
./dev.sh status # Show container status
./dev.sh rebuild # Rebuild images without cache
./dev.sh clean # Stop and remove volumes
Prerequisites: Docker only
Everything runs in Docker — intended for demos, integration testing, or sharing with non-technical users.
./local.sh up
Local mode endpoints:
| URL | |
|---|---|
| Frontend | http://localhost:4000 |
| Nginx gateway | http://localhost:9082 |
| Users service | http://localhost:9020 |
| Budget service | http://localhost:9021 |
Other local.sh commands:
./local.sh down # Stop all services
./local.sh logs [SERVICE] # Stream logs (optionally for one service)
./local.sh status # Show container status
./local.sh rebuild # Rebuild images without cache
./local.sh clean # Stop and remove volumes
./local.sh shell [SERVICE] # Open a shell in a container (default: users)
The Playwright suite (frontend-typescript/e2e/) covers the auth + budget CRUD journey — both at the API layer (api project, no browser) and through the real browser UI (browser project, chromium) — against the local-mode stack:
./local.sh up
# once containers are healthy:
npx playwright test --config=frontend-typescript/e2e/playwright.config.ts
Scope is deliberately narrow for this first suite: auth + budget CRUD only. AI chat and donor-dashboard/donor-grantee-relationship flows are excluded for now — a fast-follow, not a technical blocker; see frontend-typescript/e2e/README.md and openspec/changes/e2e-test-suite/ for the full rationale and local-run details (cleanup convention, local vs dev port notes).
GrantFlow/
├── .github/workflows/ # CI: lint + tests per service
├── docker/ # Postgres init (creates 4 DBs)
├── docker-compose.dev.yml # Infrastructure-only compose (dev mode)
├── docker-compose.local.yml # Full containerized compose (local mode)
├── docker-compose.prod.yml # Production compose (Hetzner deploy)
├── dev.sh # Dev mode entry point
├── local.sh # Local mode entry point
├── frontend-typescript/ # React + Vite + TypeScript app
├── monitoring/ # OTEL collector, Prometheus, Grafana configs
├── nginx/ # Gateway config (dev + prod)
├── scripts/ # Utility scripts (issue creation, etc.)
├── shared/ # Shared Python library
│ ├── ai_client/ # In-process client for ai-service's /ai/decide (retries, timeouts, decision parsing)
│ ├── db/ # Audit mixin, custom column types
│ ├── exceptions/ # Shared exception types
│ ├── observability/ # OpenTelemetry setup
│ ├── schemas/ # Pydantic schemas (cross-service)
│ ├── security/ # JWT utils, FastAPI auth dependencies
│ ├── services/ # Currency service, transactional email (MailerSend/Mailjet)
│ ├── storage/ # S3-compatible storage service (report attachments)
│ └── utils/ # HTTP client wrapper
├── services/
│ ├── users/ # FastAPI: users, customers, auth
│ ├── budget/ # FastAPI: budgets, budget lines
│ ├── ai/ # FastAPI: stateless LLM reasoning (/ai/decide), rate limiting, audit logs
│ ├── chat/ # FastAPI: agent host — conversations, tool registry, dispatch loop, SSE streaming
│ └── worker/ # Celery: background jobs (RabbitMQ broker, Redis result backend)
└── terraform/ # Prod infra provisioning (Hetzner Cloud)
Each service follows the same internal layout:
service/
├── app/
│ ├── api/ # Route handlers
│ ├── crud/ # DB operations
│ ├── models/ # SQLAlchemy ORM models
│ ├── schemas/ # Pydantic request/response
│ ├── services/ # Business logic
│ └── core/ # Config, logging, exceptions
├── migrations/ # Alembic versions
├── tests/
└── main.py
GitHub Actions runs on every push/PR touching a service or shared/:
| Workflow | Triggers | Steps |
|---|---|---|
users.yml | services/users/**, shared/** | black · mypy · flake8 |
budget.yml | services/budget/**, shared/** | pytest · black · mypy · flake8 |
ai.yml | services/ai/**, shared/** | pytest · black · mypy · flake8 |
chat.yml | services/chat/**, shared/** | pytest · black · mypy · flake8 |
worker.yml | services/worker/** | black · flake8 · pytest |
shared.yml | shared/** | black · flake8 · pytest (shared/ai_client, shared/tests) |
frontend.yml | frontend-typescript/** | vitest (with coverage) |
compose.yml | compose files, .env* (changed paths) | Docker Compose Validation — config lint |
e2e.yml | services/users/**, services/budget/**, shared/**, frontend-typescript/** (also workflow_dispatch) | Boots the local-mode stack · Playwright api + browser projects · teardown |
deploy.yml | push to main | Deploy to VPS over SSH (workflow_dispatch also) |
git checkout -b feature/your-featurecd services/<service> && pytestblack . && mypy . && flake8GNU AGPL v3 — see LICENSE.