SK CREATION
Live product · getauctionlist.com

AI Front Door

Get Auction List — enterprise assistant architecture

Authenticated assistant on getauctionlist.com that answers only from approved sources — policy RAG, auction SQL, and allowlisted county tools — with citation grounding and typed failure modes.

As-built · 2026-07 · auction-lens-ai (Next.js BFF) · get-auction-list-api (FastAPI + LangGraph)

Business capability

Answers only from approved sources

Enterprise constraints: browser never calls LLMs or MCP; answers are citation-grounded; failures are typed (completed / partial / failed); no invented auction rows or county dates.

CapabilityIntentRuntime path
Policy / product termsknowledge_policyHybrid RAG (chunks + embeddings)
Indexed auction filtersauction_searchDeterministic SQL on ingested rows
County schedule / WCADpublic_property_lookupAllowlisted HTTPS tools (live)
Multi-source researchcombined_researchParallel fan-out → correlate → synthesize
Refusalunsupported_or_unsafeGuardrail short-circuit

Logical architecture

Frontend → backend layers

Hard boundary: the browser never holds service-role keys and never calls OpenAI, FastAPI, or /mcp for Front Door chat.

AI Front Door logical architecture — Presentation, BFF, AI control plane, and data/tools layers
Logical architecture (frontend → backend)
LayerComponentsResponsibility
PresentationAiFrontDoorLauncher / Dialog, dashboard, lib/aiChat UX, SSE reduce, Zod shapes; dashboard parses Storage xlsx locally
Edge BFFapp/api/ai/{chat,chat/stream,feedback}Same-origin only; Supabase session → Bearer JWT; proxy to AGENT_SERVICE_URL
AI control planeFastAPI :8000, JWKS auth, ControlledAgentGraph, OpenAI structured modelsRoute, retrieve/tools, ground, synthesize, stream
Data & toolsPostgres + pgvector, Storage, PublicRecordsService / MCP, OpenAIDurable indexes, object bytes, allowlisted egress, LLM/embeddings
Workerauction-ingestion-workerOffline policy + spreadsheet ingest into Postgres

Request path

Authenticated chat flow

Authenticated chat request path from browser through BFF and FastAPI to LangGraph sources and SSE response
Authenticated chat request path
  1. 1Dialog POST /api/ai/chat/stream with message + optional thread_id
  2. 2BFF validates Supabase session and forwards Authorization: Bearer <access_token>
  3. 3API validates JWT via JWKS (same Supabase project), starts LangGraph run
  4. 4Graph: validate → route → extract → Send to RAG and/or SQL and/or public tools
  5. 5Correlate → ground → disclaimer → synthesize (LLM or deterministic fallback)
  6. 6SSE answer.delta / answer.completed → UI cards, sources, optional CTA

Stack

Technology (enterprise view)

LayerTechnologyRole
UINext.js 16, React 19, Tailwind 4, Base UIChat + dashboard
ValidationZod (FE), Pydantic (BE)Contract enforcement
BFFNext Route HandlersSession gate, SSE proxy, no browser secrets
AuthSupabase Auth + JWKSSame project FE↔BE
OrchestrationLangGraph (StateGraph, Send)Bounded intents & budgets
LLMOpenAI Responses API (gpt-4.1-mini)Classify, extract, synthesize
Embeddingstext-embedding-3-small @ 1536 dimsPolicy RAG only
Primary DBSupabase PostgreSQLAuth, auctions, RAG tables, jobs
Vector / keywordpgvector + tsvector (english)Hybrid retrieve
Object storeSupabase Storage auction_filesMonthly xlsx bytes
Public toolsFastMCP Streamable HTTP /mcpOps tooling; graph uses in-process service
HTTP egressApprovedHttpClientHost allowlist, SSRF-safe
ObsPrometheus /metrics, optional OTEL / LangfuseNo prompt/PII dump

Control plane

ControlledAgentGraph nodes

One typed LangGraph orchestrator — bounded intents and budgets, not unconstrained ReAct.

ControlledAgentGraph control plane from validation through capability fan-out to grounded synthesis
Control plane — agent graph
NodeResponsibility
validationLength ≤ 4000; injection heuristic
routingHeuristics + optional OpenAIIntentClassifier
extractionDeterministic entities + optional OpenAIEntityExtractor
knowledge_ragHybrid RAG — policy chunks only
sql_auction_searchsearch_auction_records filters
mcp_public_toolsCounty calendar / WCAD live tools
grounding_verificationDrop uncited / ungrounded facts
compliance_disclaimerAuction/public intents
synthesisGrounded LLM or deterministic fallback

Data planes

Three retrieval paths — RAG is only one

Dashboard Excel parse is a fourth UX path (browser-only) and is never the AI graph’s search source.

PlaneOfflineOnlineVector?
Policy RAGYes — ingest URLsHybrid retrieve + LLMYes
Auction indexYes — ingest xlsxSQL filters (+ CTA to dashboard)No
Public recordsOptional registry onlyLive scrape each askNo

Security

Tenancy & trust boundary

  • Trust boundary at BFF; API re-validates JWT (same Supabase project).
  • Default role user: auction:read, document:read, tool:execute.
  • Egress allowlist; MCP bearer for service callers only.
  • Telemetry sanitizes secrets / PII; chat responses Cache-Control: no-store.
  • Browser never holds service-role keys and never calls OpenAI, FastAPI, or /mcp for Front Door chat.

Decisions

Architecture choices

  1. 1.One typed LangGraph orchestrator — not unconstrained ReAct or peer agents.
  2. 2.SQL for auction filters; hybrid RAG only for unstructured policy.
  3. 3.Live allowlisted tools for county/WCAD — no arbitrary browsing.
  4. 4.Grounded synthesis + deterministic fallbacks.
  5. 5.Expand/contract schema migrations; architecture docs stay with behavior changes.