Skip to content

Repository files navigation

LandDoc Intelligence

An ASP.NET Core (.NET 10) Web API + React/TypeScript SPA running a retrieval-augmented Q&A vertical slice over land/title documents: ingest a PDF (or .txt/.md) → extract structured fields → chunk → embed → top-k similarity retrieval → answer with citations. Each ingested document is persisted (original file + metadata), so you also get a documents table and a source-file viewer, and every citation links back to the document it came from.

It is deployed — a single container on Azure Container Apps, secrets pulled from Key Vault via managed identity, CI/CD on merge to main (see DEPLOYMENT.md + ADR-0016). It is not production-hardened — RBAC, observability, VNet/Private Link and the like are deliberately out of scope (see CLAUDE.md); access is gated to the owner's Microsoft account (ADR-0022).

Senior-level judgment made visible: deliberate scope (build vs. stub), a spec- and ADR-first workflow, and an agentic process that's part of the deliverable.

How it works

  • Ingest (POST /documents) — parse PDF / decode text → extract fields (best-effort) → chunk → embed → store chunks in the vector store and persist the original file + metadata in the document store.
  • Ask (POST /ask) — embed the question → retrieve top-k chunks across the whole corpus → answer grounded only in those passages, cite-or-error (an answer always carries ≥1 citation, or it 409s on an empty store).
  • Read back (GET /documents, GET /documents/{id}, GET /documents/{id}/file) — list documents with their fields, and open the original file inline in the viewer.
  • Explore (Dashboard tab) — KPI tiles, documents-by-location and ingest-over-time charts, a needs-review list, and lease expirations — all aggregated client-side from GET /documents; the documents table also adds search + CSV export.
  • Delete (DELETE /documents/{id}) — multi-select removal of documents from both stores (chunks + file/metadata); idempotent.
  • Monitor (GET /usage, Ops / Usage tab) — LLM token usage, estimated cost, request health (success / 4xx / 429 / 5xx), and latency, read live from free Azure Monitor platform metrics (ADR-0020).

Ports & adapters — provider choice is config, not code

Every external dependency sits behind an interface with a live adapter (production default) and an offline adapter (used by the test suite, no cloud credentials). Swapping is a config-section change, never a code change.

Port Live default Offline / fallback
IChatClient Azure OpenAI gpt-5.4-mini (ADR-0012) Anthropic claude-opus-4-8 (config-swap fallback)
IEmbeddingClient Azure OpenAI text-embedding-3-small, 256-d (ADR-0013) Local deterministic hashing (offline/test)
IVectorStore Azure AI Search Free tier (ADR-0017) In-memory cosine (offline/test)
IDocumentStore Azure Blob Storage (ADR-0018) In-memory (offline/test)
IUsageSource Azure Monitor platform metrics (ADR-0020) In-memory (offline/test)

Quickstart

Backend (backend/) — ASP.NET Core, .NET 10:

dotnet build
dotnet test                              # fully offline — pins the in-memory + local adapters
dotnet run --project src/LandDoc.Api     # listens on http://localhost:5084

Frontend (frontend/) — React + TS + Vite:

npm install
npm run dev                              # http://localhost:5173, dev-proxies /documents + /ask to the API
npm test                                 # Vitest + React Testing Library (mocked client)

Run with no cloud credentials by pinning the offline providers (defaults in tests): ModelClient__EmbeddingProvider=local, ModelClient__ChatProvider=anthropic (needs an Anthropic key) or a fake, VectorStore__Provider=inmemory, DocumentStore__Provider=inmemory. See RUNBOOK.md for all config keys.

Repo map

Docs are authored as design intent before code; once code lands, /wrap keeps them current.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages