Aequitas FI is a production-oriented hybrid SQL + RAG financial dashboard: structured analytics over Postgres (compatible with Supabase) and grounded answers using pgvector retrieval, orchestrated with LangGraph stateful agents and a Next.js front end.
Aequitas FI is an AI engineering portfolio build that demonstrates agentic orchestration and tight product UX (“vibe” UI): a multi-agent router where OpenAI o3–class models (configurable, default o3-mini) own read-only Text-to-SQL and Claude 3.5 Sonnet (or GPT via override) handles RAG-aware synthesis and narrative, with a PII redaction layer (Presidio) on the synthesis path, LangGraph checkpoints for the Temporal (compare periods) flow, and a transparency/audit trail (prompt, SQL, RAG chunks, model versions, human feedback) suitable for financial governance demos.
| Capability | How it is expressed in this repo |
|---|---|
| Hybrid SQL + RAG | packages/ai-core/aequitas_ai/sql_engine.py (Architect → Validator → execute) + rag_engine.py + FastAPI POST /v1/insight/stream and Next /api/insight/stream. |
| Temporal “time travel” | packages/ai-core/aequitas_ai/agents/temporal_agent.py + WebSocket /v1/temporal/ws (UI: Compare mode). |
| PII redactor | apps/server/middleware/redactor.py around selected LLM calls. |
| CI | .github/workflows/ai-pipeline.yml — Prettier, ESLint, pytest, optional DeepEval when OPENAI_API_KEY is set in repository secrets. |
| Layer | Technology | Role |
|---|---|---|
| Frontend | Next.js (App Router), Tailwind CSS, Lucide icons, shadcn/ui (configured via components.json) |
Monochrome, dark-first dashboard UI. |
| API & orchestration | FastAPI, LangGraph | REST/streaming entrypoints, stateful agent graphs: SQL path, RAG path, and synthesis. |
| Data | SQLAlchemy 2, Alembic | Models and migrations; targets Postgres 16 + pgvector (same feature set you use in Supabase). |
| AI (split responsibilities) | o3-mini (SQL), Claude 3.5 Sonnet (synthesis) | o3-mini produces read-only SQL from schema + question; Sonnet fuses tabular results and retrieved chunks into final narrative. |
| Shared Python | packages/ai-core (aequitas_ai) |
Prompts (prompts/), graph state (agents/state.py), future LangGraph nodes here. |
| Shared database | packages/database (aequitas_database) |
Schemas, Alembic migrations, async session helpers. |
flowchart LR
UI[Next.js app] --> API[FastAPI]
API --> G[LangGraph]
G --> SQL[o3-mini SQL]
G --> RAG[pgvector RAG]
SQL --> DB[(Postgres + pgvector)]
RAG --> DB
G --> Syn[Claude 3.5 Sonnet]
Syn --> API
API --> UI
- Supabase in production: point
DATABASE_URL/SYNC_DATABASE_URLat the Supabase connection string; keep pgvector enabled for the same migration story as local Docker.
- Intent: user question in the command bar (Hybrid insight).
- SQL graph: Architect → Validator (lint / forbidden DML) → read-only
SELECT(execute). - RAG: optional Supabase
match_rag_chunks(or your RPC) whenSUPABASE_URL+ service key and embeddings are set. - Synthesis: narrative with mandatory sources (SQL + document metadata) and a trend keyword tie-in to RAG text where applicable.
- Audit: an
audit_logsrow is opened and completed for each stream; Thumbs usehuman_feedbackwhen the BFF is enabled.
Compare periods uses the same DB but the Temporal LangGraph over WebSocket (with Postgres checkpointer when USE_POSTGRES_CHECKPOINTER is true and the DB is reachable; otherwise in-memory). On Windows, the API sets a selector event loop so psycopg works with the LangGraph Postgres checkpointer.
.
├── apps/
│ ├── web/
│ │ ├── app/ # dashboard, research, alerts, portfolio, debate, reports, admin
│ │ ├── components/ # dashboard, charts, ai, ui
│ │ └── lib/ # api adapters, hooks, streams/ws, supabase
│ └── server/
│ ├── app/ # routers, auth, graph registry, services, rbac
│ ├── api/ # ingest + debate orchestration
│ └── middleware/ # redactor, rate limiter, request id
├── packages/
│ ├── database/ # aequitas_database models + Alembic migrations
│ └── ai-core/ # agents, prompts, tools, sql/rag engines
├── infra/
│ ├── docker-compose.yml # Local Postgres + Redis (pgvector image)
│ ├── docker-compose.prod.yml # Production stack
│ └── nginx/nginx.conf # Reverse proxy template
├── .github/workflows/
│ ├── ai-pipeline.yml
│ └── deploy.yml
├── requirements-local.txt
└── README.md
- Node.js 20+ (for the web app)
- Python 3.11+ (for API and packages)
- Docker (for
docker-composedatabase)
From the repository root:
docker compose -f infra/docker-compose.yml up -dDefault Postgres connection (matches infra/docker-compose.yml):
- URL (async, e.g. SQLAlchemy):
postgresql+asyncpg://aequitas:aequitas_dev@localhost:5432/aequitas - URL (sync, e.g. Alembic with psycopg2):
postgresql+psycopg2://aequitas:aequitas_dev@localhost:5432/aequitas
Migrations (from packages/database):
# optional: set SYNC_DATABASE_URL for non-default host/user/db
set SYNC_DATABASE_URL=postgresql+psycopg2://aequitas:aequitas_dev@localhost:5432/aequitas
cd packages/database
..\.venv\Scripts\alembic upgrade head(Use alembic from the same venv that has the package installed, or python -m alembic after pip install -e ..)
Start production-shaped services (API + Postgres + Redis):
docker compose -f infra/docker-compose.prod.yml up -d --buildNginx reverse proxy template: infra/nginx/nginx.conf.
From the repository root:
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements-local.txtThis installs, in order: aequitas-database, aequitas-ai, and the FastAPI app in apps/server.
Run the API:
cd apps\server
uvicorn app.main:app --reload --port 8000- Health: http://127.0.0.1:8000/health
- Copy
apps\server\.env.exampleto.envand set API keys and model names as you wire providers.
From apps/web (or use npm / pnpm with workspace scripts when pnpm is available):
cd apps\web
npm install
npm run dev- App: http://127.0.0.1:3000
- shadcn/ui: run
npx shadcn@latest add <component>insideapps/webto add components tocomponents/ui/.
Configured in apps/server/app/config.py (and overridable via environment):
sql_model— defaulto3-minifor SQL generation.synthesis_model— defaultclaude-3-5-sonnet-20241022for final answers.
Wire your provider clients (OpenAI, Anthropic, or unified gateways) in the LangGraph nodes as you build them.
.github/workflows/ai-pipeline.yml—push/pull_requestonmain: Prettier + ESLint onapps/web,pip install -r requirements-local.txt+testing_suitedeps,pytest, faithfulness demo script, optional DeepEval whenOPENAI_API_KEY(and for full RAG tests, Supabase secrets as configured) is present..github/workflows/github-action.yml— additional secret scan and builds on a broader set of branches; keep in sync with your branch strategy..github/workflows/deploy.yml— automated deployment pipeline for Cloudflare Pages (frontend via Git integration) and Cloudflare Workers (backend), including smoke checks.
Secrets (AI eval job): add OPENAI_API_KEY; optionally SUPABASE_URL and SUPABASE_SERVICE_KEY for tests that call vector RPCs.
Deployment validation + smoke automation scripts are in scripts/deploy/:
smoke-check.jsfor post-deploy health verification against Pages + Worker endpoints.- Frontend deployment is automatic in Cloudflare Pages when
main/developis pushed. - Backend deployment is handled by GitHub Actions using Wrangler.
Full runbook: docs/deployment-runbook.md.
Cutover checklist: docs/cloudflare-cutover-checklist.md.
- SQL safety: only read-only SQL from the LLM; validate and execute in a restricted DB role in production.
- Vectors:
document_embeddingsuses HNSW (cosine) in the initial migration; align embedding dimension (1536placeholder) with your embedding model in both Alembic andDocumentEmbedding. - Reserved names: the JSON column is named
chunk_metadata(notmetadata) to avoid clashing with SQLAlchemy’sBase.metadata.
Internal codename: Aequitas FI — hybrid financial intelligence stack.