NNora the Policy Navigator

Deliverables

What we've shipped

M7In Progress

Architecture Diagram

Nora is a client-server web application with three tiers: a React app in the user's browser, a FastAPI server, and a PostgreSQL database. It works by request and response, and is not event-driven or real-time. The server answers questions with retrieval-augmented generation (RAG): it finds the relevant policy passages first, then has an LLM write an answer from them.

Nora architecture diagramResearchers and admins use a web browser to reach Nora over the internet. On Carolina CloudApps, UNC Shibboleth sign-in sits in front of an nginx web container serving the React app, which forwards API calls to a FastAPI container. The API reads and writes a PostgreSQL database with pgvector, and calls third-party LLM and embedding APIs over the internet. Admins curate documents by hand from the existing UNC Policy Knowledge Base.USERSResearcherweb browser,desktop or phoneAdministratorUNC Research staff,web browserUNC PolicyKnowledge Basepolicies.unc.edu9 categories · <200 docscurated by hand,no live syncINTERNET · HTTPSCAROLINA CLOUDAPPS (OPENSHIFT)UNC Shibboleth SSO (Onyen)production sign-in · mock login during the semesterWeb container · nginx + React appserves the UI · forwards /api/* to the APIAPI container · FastAPI (Python)REST JSON API under /apiAuth & rolesBrowse & searchAsk · RAG pipelineAdmin & analyticsDocument ingestion: chunk + embed policiesPostgreSQL + pgvectorpolicies · embeddings · users · questions · feedbackINTERNETTHIRD-PARTYLLM APIwrites cited answersClaude in development;needs UNC approvalEmbedding APItext → vectorsprovider TBD; localmodel as fallbackJSONSQL · vector search
  • Our work
  • Existing UNC or third-party, which we adapt to
  • Inside CloudApps (fast, internal network)
  • Over the internet (much slower)

Scroll sideways to see the whole diagram.

Where Things Run

The user's browser

Researchers and admins are the outside world. Their browser, on any desktop or phone, runs the React app and sends every request across the internet.

Carolina CloudApps

UNC's servers run our web container, API container, and database. Traffic between them stays on CloudApps' internal network.

Third-party AI services

The LLM and embedding providers run on their own servers. Each call crosses the internet, which is why an answer takes seconds, not milliseconds (spec NF8).

Data Flow: Asking a Question

  1. 1

    The researcher types a question in the browser, which sends it to /api over HTTPS.

  2. 2

    The API turns the question into a vector with the embedding API.

  3. 3

    pgvector finds the policy passages closest in meaning to the question.

  4. 4

    If nothing relevant enough is found, Nora says so and points the researcher to the right compliance office, without calling the LLM.

  5. 5

    Otherwise the API sends the question and those passages to the LLM, which writes a plain-language answer that cites them.

  6. 6

    The API saves the question, whether it was answered, and later any feedback, which feed the admin dashboard, and returns the answer with its sources.

Components

Scaffolded means the piece exists in our repository as a working skeleton; Planned means we haven't connected to it yet.

  • Web container (nginx + React)

    OursScaffolded

    Runs in the user's browser once loaded: the researcher views (Browse, Search, Ask) and the admin portal. In production, an unprivileged nginx serves the built app on port 8080 and forwards /api/* to the API, so the browser only ever talks to one origin.

  • API container (FastAPI)

    OursScaffolded

    All application logic, behind a JSON API under /api: resolving the user and their role, keyword search and topic browsing, the Ask pipeline, admin content management and analytics, and ingesting new documents. Only a health check exists so far.

  • PostgreSQL + pgvector

    OursScaffolded

    The single data store: policy documents and their chunks with embeddings, users and roles, questions asked, and feedback. Our first migration enables pgvector; the tables come next.

  • UNC Shibboleth SSO

    Existing (UNC)Planned

    UNC's Onyen sign-in. We adapt to it rather than build it: in production it will likely sit in front of the app and pass the user's identity in, with the exact pattern still to confirm with UNC ITS. Until then we use a mock login that models it.

  • Carolina CloudApps

    Existing (UNC)Planned

    UNC's OpenShift platform, which runs our containers. It requires non-root images that work under any user ID, which ours already do.

  • UNC Policy Knowledge Base

    Existing (UNC)Planned

    The source of Nora's content. There is no live connection: admins choose documents and upload them through the admin portal.

  • LLM and embedding APIs

    Third-partyPlanned

    External AI services reached over the internet. Both sit behind interfaces in the API so the provider can change once UNC approves one, and so tests never call them.

Development vs. Production

On a laptop (Docker Compose)In production (CloudApps)
Serves the React appVite dev server, port 5173, hot reloadnginx-unprivileged, port 8080
Forwards /api/*Vite's dev proxynginx proxy_pass
APIFastAPI with --reload; runs migrations on startFastAPI as a non-root user
Databasepgvector/pgvector:pg17 containerPostgreSQL + pgvector on UNC infrastructure
Sign-inMock Onyen loginUNC Shibboleth SSO