Skip to content
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 write AgentRuns; workflows write WorkflowRun + WorkflowStep rows. 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

The one-diagram version

Rendering diagram…

Architectural invariants

These hold everywhere in the codebase; breaking one is a bug:

  1. Routers never call OpenAI directly. All LLM access goes through services/ (Backend).
  2. Every LLM/tool step is logged as a ToolCall, with model_name, estimated_tokens, estimated_cost, and latency_ms where available (Observability).
  3. Tool access is enforced per agent via the enabled_tools allow-list before any tool executes (Tools).
  4. Vector data is agent-scoped. Every Chroma query filters where={"agent_id": ...} so agents can never read each other's documents (Retrieval).
  5. Agents own their data. All child rows cascade-delete with their agent (cascade="all, delete") (Database Schema).
  6. The frontend never talks to OpenAI. It only ever calls the backend.