3 min read · 539 words
Architecture
VeyraOps AI is a deliberately simple three-tier system — Next.js frontend, FastAPI backend, local storage (SQLite + Chroma) — with one non-negotiable invariant: every automated step is observable.
Executive summary
- The frontend is a thin presentation layer. Server components fetch read-only data directly from the backend; mutations go through Next.js route handlers acting as a backend-for-frontend proxy.
- The backend is a layered FastAPI service: routers validate and orchestrate, services encapsulate all LLM/vector logic, SQLAlchemy models persist state.
- Two storage engines: SQLite for relational state (agents, messages, runs, tasks, tool calls, documents, workflows) and Chroma for vector embeddings, scoped per agent.
- One observability contract: every LLM or tool step writes a
ToolCall; chats writeAgentRuns; workflows writeWorkflowRun+WorkflowSteprows. The dashboard is a pure aggregation over these tables. - No authentication, no queues, no websockets — by design at this stage; see Security and the Roadmap.
Section map
[System Overview](system-overview.md)The full component diagram, the six layers of the backend, and how the two storage engines divide the work.System Overview
[Request Lifecycle](request-lifecycle.md)A chat request traced end-to-end: browser → FastAPI → OpenAI → SQLite → response, with the exact sequence diagram.Request Lifecycle
[Data Flow](data-flow.md)How data moves through the email workflow and the RAG pipeline, including what gets persisted where.Data Flow
[Security](security.md)The honest current posture (no auth, local-only) and the hardening checklist for production.Security
[Design Decisions](design-decisions.md)Why FastAPI, why SQLite, why Chroma, why LangGraph, why the frontend proxies — trade-offs stated explicitly.Design Decisions
The one-diagram version
Rendering diagram…
Architectural invariants
These hold everywhere in the codebase; breaking one is a bug:
- Routers never call OpenAI directly. All LLM access goes through
services/(Backend). - Every LLM/tool step is logged as a
ToolCall, withmodel_name,estimated_tokens,estimated_cost, andlatency_mswhere available (Observability). - Tool access is enforced per agent via the
enabled_toolsallow-list before any tool executes (Tools). - Vector data is agent-scoped. Every Chroma query filters
where={"agent_id": ...}so agents can never read each other's documents (Retrieval). - Agents own their data. All child rows cascade-delete with their agent (
cascade="all, delete") (Database Schema). - The frontend never talks to OpenAI. It only ever calls the backend.
Related pages
- Backend Overview — the code that implements this architecture
- Database Schema — the ERD
- Deployment — how the pieces are hosted