Nquiry Architecture Reference
For Joe — written to explain the technical underpinnings without assuming developer knowledge.
Last updated: February 16, 2026 (last reviewed 2026-04-29)
1. What Nquiry Is Made Of
Nquiry is a web application. When you open app.nquiry.ai in a browser, you're interacting with a system that has three main layers: the frontend (what you see), the backend (the logic that processes your requests), and services (databases, file storage, AI, authentication).
What makes Nquiry's architecture somewhat unusual is that the frontend and backend are bundled together in a single application rather than being separate systems. This is a deliberate choice — it simplifies deployment and reduces the number of moving parts.
The Application Framework: Next.js
Next.js is the framework everything is built on. Think of it as the skeleton of the application. It handles both what the user sees (pages, buttons, forms) and what happens behind the scenes (talking to the database, calling the AI, enforcing permissions).
Version: Next.js 16, running on Node.js 24.
Next.js uses something called the App Router, which means each page in the application corresponds to a folder in the codebase. For example, the page you see at /inquiries/[id]/evidence is defined by a file at app/(protected)/inquiries/[id]/evidence/page.tsx. This is useful to know because when CC reports working on a file path, you can map it to what you see in the browser.
The Language: TypeScript
All code is written in TypeScript, which is JavaScript with added type safety. Type safety means the code explicitly declares what kind of data it expects — "this function takes a string and returns a number" — and the computer checks those declarations before the code runs. This catches a category of bugs at build time rather than in production.
The UI Components: React + Tailwind + shadcn/ui
React is the library that builds the interactive interface. Every button, form, table, and panel you see is a React "component" — a reusable piece of UI with its own behavior.
Tailwind CSS handles visual styling (colors, spacing, layout) through utility classes rather than custom stylesheets.
shadcn/ui is a component library that provides pre-built, accessible UI elements (dialogs, dropdowns, tabs, cards). It gives the app a consistent, professional look without building every element from scratch.
2. How the Pieces Connect (Request Flow)
When you click something in the browser, here's what happens:
Your Browser
↓ HTTPS request
CloudFront (CDN / Edge)
↓ forwards to origin
ALB (Load Balancer)
↓ routes to healthy container
ECS Container (the running app)
↓ internally handles:
├── Page rendering (React components)
├── API logic (database queries, AI calls)
├── Authentication check (via Cognito)
├── File operations (via S3)
└── AI operations (via Bedrock)
↓ response
Back up through ALB → CloudFront → Your Browser
Each layer explained:
CloudFront is AWS's content delivery network. It sits in front of everything and does two jobs: serves cached static content (images, CSS, JavaScript files) quickly from edge locations near you, and forwards dynamic requests (API calls, page loads) to the application. It also handles the SSL certificate — this is why the NQU-187 bug (where your browser was hitting the ALB directly instead of going through CloudFront) caused a certificate error.
ALB (Application Load Balancer) receives requests from CloudFront and routes them to whichever ECS container is healthy. Right now there's only one container running, but the ALB is what would enable scaling to multiple containers if needed.
ECS Container is the actual running application. This is where Next.js processes your request, queries the database, calls the AI, and sends back a response. More on ECS in Section 3.
3. Where the App Runs: ECS/Fargate
Before the February 12 migration (NQU-160), Nquiry ran on AWS Amplify, which is a simpler but more limited hosting service. The migration to ECS (Elastic Container Service) on Fargate was necessary because Amplify couldn't connect to the database inside a private network (VPC).
Containers: The Core Concept
A container is a packaged version of the application with everything it needs to run — the code, Node.js runtime, and dependencies — bundled into a single image. Think of it like a self-contained appliance: plug it in and it runs, regardless of what else is on the host machine.
The container image is built by the CI pipeline (see Section 6) and stored in ECR (Elastic Container Registry) — AWS's container image storage.
How ECS/Fargate Works
ECS is the orchestration service — it decides when to start, stop, or restart containers. Fargate is the compute engine — it provides the actual server resources without you managing physical servers.
Key concepts:
- Cluster: The logical grouping (
invapp-dev-cluster). Contains services. - Service: Defines how many containers should be running and keeps them running (
invapp-dev-app-service). If a container crashes, the service automatically starts a new one. - Task Definition: The blueprint for a container — what image to use, how much CPU/memory, what environment variables to set, what ports to open. Each deploy creates a new task definition revision.
- Task: A running instance of a task definition. This is the actual container doing work.
Current configuration: 1 task running, 0.5 vCPU, 1 GB memory. This is sized for development/early production — enough for a handful of concurrent users.
ECS Exec
CC enabled ECS Exec (NQU-179) which lets you run commands inside the running container. This is how diagnostic scripts and database operations are run against the production database — by exec-ing into the container that already has network access to RDS.
4. AWS Services Map
Here's every AWS service Nquiry uses and what it does:
Compute & Networking
| Service | Resource Name | What It Does |
|---|---|---|
| ECS/Fargate | invapp-dev-cluster / invapp-dev-app-service | Runs the application container |
| ECR | invapp-dev-app | Stores container images (like a library of app versions) |
| CloudFront | Distribution for app.nquir.ai | CDN + SSL termination + caching |
| ALB | invapp-dev-alb | Load balancer routing traffic to ECS |
| VPC | invapp-dev-vpc | Private network containing all infrastructure |
| Route 53 | Hosted zone for nquiry.ai | DNS management (domain → IP resolution) |
Data Storage
| Service | What It Does |
|---|---|
| RDS (PostgreSQL) | The database. Stores everything: inquiries, evidence metadata, analysis results, user data, prompt templates, audit logs. Single instance, not publicly accessible (secured inside VPC). |
| S3 | File storage. Three buckets: evidence, evaluation-guides, framework-documents. Files are encrypted at rest and accessed via signed URLs (temporary, expiring links). |
| ElastiCache (Redis) | In-memory cache. Used for session data and rate limiting. Fast but ephemeral — data is lost on restart, which is fine for its purpose. |
Authentication & Security
| Service | What It Does |
|---|---|
| Cognito | User authentication. Handles signup, login, password reset, MFA (TOTP). Issues tokens that the app validates on every request. You never see Cognito directly — it works behind the login page. |
| ACM | Certificate Manager. Manages SSL certificates for *.nquiry.ai. CloudFront uses these to serve HTTPS. |
| WAF | Web Application Firewall. Attached to CloudFront. Blocks common attack patterns (SQL injection, XSS) before they reach the app. |
AI
| Service | What It Does |
|---|---|
| Bedrock | The AI service. Nquiry calls Bedrock to run Claude (Anthropic's model) for analysis generation, faithfulness checking, evidence summarization, and structured output. All AI calls go through Bedrock — your evidence stays within AWS, never leaves to external APIs. |
| Bedrock (Titan Embeddings V2) | Converts text into mathematical representations (embeddings) for semantic search. When evidence is uploaded, each chunk gets an embedding. When you run analysis, the question gets an embedding, and the system finds evidence whose embeddings are mathematically similar. |
Monitoring & Operations
| Service | What It Does |
|---|---|
| CloudWatch | Logging and monitoring. Application logs, ECS container metrics, ALB request logs all flow here. Where CC looks when diagnosing issues. |
| Bedrock Guardrails | Safety filters on AI inputs/outputs. Prevents the AI from generating harmful content or processing certain categories of sensitive input. |
Infrastructure as Code
| Service | What It Does |
|---|---|
| Terraform | Not an AWS service, but a tool that defines all the above infrastructure as code files. Instead of clicking through the AWS console to create resources, Terraform files describe what should exist, and terraform apply makes it so. This means infrastructure is version-controlled, reviewable, and reproducible. Lives in infrastructure/terraform/. |
5. The Database
PostgreSQL on RDS
The database is PostgreSQL, running as a managed service on Amazon RDS. "Managed" means AWS handles backups, patching, and failover — you don't maintain a database server.
The database stores virtually everything: inquiry structure (inquiries, topics, questions, evidence metadata), analysis results and quality metrics, prompt templates and version history, user accounts and organization membership, audit logs, embedding vectors for semantic search (using pgvector extension), and billing and subscription data.
Key Tables (the important ones)
| Table | What It Stores |
|---|---|
investigation | Your inquiries — title, focus statement, type, status |
evidence | Evidence items — title, type, source, file references |
evidence_chunk | Text segments of evidence, with embeddings for search |
investigation_question | Questions within topics |
analysis | AI-generated analyses with quality scores, prompt version tracking |
analysis_evidence_retrieval | Which evidence was retrieved for each analysis + similarity scores |
evidence_question_link | Your manual evidence-to-question links |
prompt_template | Current prompt text for each analysis type |
prompt_template_history | Full version history of every prompt change |
audit_log | Every significant action (who, what, when, from where) |
organization | Orgs and tenant isolation boundaries |
organization_member | Who belongs to which org, with what role |
Migrations
Database structure changes are managed through migrations — numbered SQL files that modify the schema in a controlled, sequential way. Each migration has an "up" (apply change) and "down" (reverse change). They live in lib/db/migrations/ and are run with npm run db:migrate. This is why when CC completes work that changes the database structure, there's a migration file that needs to be run.
6. How Code Gets Deployed (CI/CD)
CI/CD stands for Continuous Integration / Continuous Deployment. It's the automated pipeline that takes code changes and gets them running in production.
The Pipeline (.github/workflows/ci.yml)
When CC pushes code to the main branch on GitHub:
Push to main
↓
┌─────────────────────────────────────────────────┐
│ lint-and-build (parallel with security-scan) │
│ • ESLint (code quality rules) │
│ • TypeScript type-check (catches type errors) │
│ • Next.js build (compiles the application) │
├─────────────────────────────────────────────────┤
│ security-scan (parallel) │
│ • Semgrep static analysis (finds security │
│ patterns like SQL injection, XSS, secrets) │
├─────────────────────────────────────────────────┤
│ test (after lint-and-build passes) │
│ • ~1,993 automated tests (unit + integration) │
│ • Coverage threshold check │
├─────────────────────────────────────────────────┤
│ e2e-tests (after test passes, main only) │
│ • Playwright browser tests │
│ • Currently failing (NQU-182: TOTP enrollment) │
├─────────────────────────────────────────────────┤
│ deploy (after lint, test, security all pass) │
│ • Skip if only docs/test changes │
│ • Build Docker image │
│ • Push to ECR with SHA tag │
│ • Register new ECS task definition │
│ • Update ECS service → rolls out new container │
│ • Wait for service stability │
└─────────────────────────────────────────────────┘
The entire pipeline takes roughly 15-25 minutes. If any step before deploy fails, deploy doesn't run — this is the safety gate.
What "Deploy" Actually Does
- Builds a Docker image containing the compiled application
- Tags it with the git commit SHA (so you can trace any running container back to exact code)
- Pushes the image to ECR
- Registers a new task definition revision with the new image
- Updates the ECS service to use the new task definition
- ECS starts a new container with the new image, health-checks it, then drains the old container
This is a rolling deployment — there's a brief period where both old and new containers are running, then the old one shuts down. Users experience zero downtime.
7. How the AI Analysis Pipeline Works
This is the technical version of what's described in the user-facing "Understanding How Nquiry Works" document.
Evidence Ingestion
User uploads file
↓
Text extraction (PDF → text, DOCX → text, etc.)
↓
Chunking (split into ~500-token segments with overlap)
↓
Embedding (each chunk → 1024-dimensional vector via Titan V2)
↓
Storage (chunk text + embedding → evidence_chunk table with pgvector)
↓
Summary generation (AI summarizes the full evidence item)
Analysis Generation
User requests analysis for a question
↓
Evidence Retrieval
├── Semantic search: question embedding ↔ chunk embeddings (cosine similarity)
├── Manual links: evidence_question_link table
├── Background docs: flagged include-in-analysis
└── Framework docs: policies, standards
↓
Context Assembly
├── Rank by relevance (similarity score + manual link boost)
├── Fill context budget (most relevant first)
└── Record what was included/excluded
↓
Prompt Construction
├── System prompt (Evidence Evaluation Framework)
├── Investigation context (title, focus, type, phase)
├── Question + direction
├── Retrieved evidence (formatted with IDs for citation)
├── Background & framework documents
└── Prior analyses (for topic/summary level)
↓
Bedrock API Call (Claude model)
↓
Structured Output Parsing (Zod schema validation)
↓
Quality Checks
├── Faithfulness check (separate AI call: are claims supported?)
├── Coverage check (separate AI call: are all question elements addressed?)
└── Schema validation (structural completeness)
↓
Storage (analysis + quality scores + retrieval metadata → database)
↓
Display to user with quality badges, citations, Evidence Considered panel
Prompt Templates
The AI prompts are stored in the database (prompt_template table), not hardcoded. Each prompt has a version number. When CC or Claude modifies a prompt, a new version is created and the old one is preserved in prompt_template_history. Every analysis record stores which prompt version produced it, so you can trace any output back to its exact instructions.
Current prompt types: analysis_question, analysis_topic, analysis_summary, evidence_summary, gap_analysis, error_check, faithfulness_check, coverage_check, and several others.
8. Testing
Test Types
| Type | Count | What It Tests | Location |
|---|---|---|---|
| Unit tests | ~1,700 | Individual functions in isolation | __tests__/unit/ |
| Integration tests | ~290 | Multiple components working together (API routes, database queries) | __tests__/integration/ |
| E2E tests | ~3 | Full browser flows (login, navigate, interact) | __tests__/e2e/ |
| Prompt tests | Subset of integration | AI prompt output structure and validation | __tests__/integration/prompts/ |
Test Framework
Tests use Vitest (unit/integration) and Playwright (E2E). Vitest is fast and runs in Node.js. Playwright automates a real browser (Chromium) to test what users actually experience.
What Tests Catch
When CC makes a change and pushes, the test suite verifies that existing functionality still works correctly. If CC changes how evidence retrieval works and it breaks the analysis API route, an integration test will fail and block the deploy. This is the primary safety net against regressions.
9. Repository Structure
The codebase lives in two GitHub repositories:
investigation-app (the main application)
investigation-app/
├── app/ # Pages and API routes (Next.js App Router)
│ ├── (auth)/ # Login, signup pages
│ ├── (protected)/ # Authenticated pages (inquiries, settings)
│ └── api/ # Backend API endpoints
├── components/ # Reusable UI components
├── lib/ # Shared logic
│ ├── ai/ # AI integration (prompts, validators, schemas)
│ ├── audit/ # Audit logging
│ ├── billing/ # Subscription plans, trial logic
│ ├── db/ # Database client, migrations, queries
│ ├── investigation/ # Access control, investigation logic
│ └── organization/ # Multi-tenant organization logic
├── infrastructure/
│ └── terraform/ # All AWS infrastructure as code
├── docs/ # Documentation (you are here)
├── __tests__/ # All tests
├── .github/workflows/ # CI/CD pipeline
├── CLAUDE.md # Instructions for CC
└── package.json # Dependencies and scripts
nquir-landing (the marketing site)
The landing page at nquiry.ai is a separate, simpler Next.js app. It's static content — no database, no authentication, no AI. It exists to explain what Nquiry is and collect early-access signups. Currently hosted on Amplify (not ECS).
10. Key Terminology Quick Reference
| Term | What It Means |
|---|---|
| API route | A backend endpoint that handles a specific request (e.g., POST /api/analysis/generate) |
| Container | A packaged, runnable version of the application |
| Context window | The maximum amount of text the AI can process in one call |
| CORS | Cross-Origin Resource Sharing — browser security rules about which domains can talk to each other |
| Embedding | A mathematical representation of text meaning (a list of ~1,024 numbers) |
| Environment variable | A configuration value set outside the code (database URL, API keys, feature flags) |
| Migration | A versioned database schema change |
| ORM | Object-Relational Mapping — a layer between code and database (Nquiry uses raw SQL via pg client, not an ORM) |
| PR (Pull Request) | A proposed code change on GitHub, reviewed before merging |
| Rolling deployment | Deploying new code by starting new containers before stopping old ones |
| Schema | The structure definition — either database tables/columns or AI output format (Zod schemas) |
| Semantic search | Finding content by meaning similarity rather than keyword matching |
| Task definition | ECS blueprint specifying container image, resources, and configuration |
| Terraform | Tool that defines infrastructure as code files |
| VPC | Virtual Private Cloud — an isolated network within AWS |
| Zod | A TypeScript library that validates data shapes (used to verify AI output structure) |
11. Cost Centers
Where Nquiry spends money on AWS:
| Service | Approximate Monthly Cost | What Drives It |
|---|---|---|
| RDS | Largest line item | Database instance running 24/7, storage |
| ECS/Fargate | Second largest | Container running 24/7 (0.5 vCPU, 1GB RAM) |
| Bedrock | Variable | AI API calls — proportional to analysis volume |
| S3 | Minimal | File storage, grows with evidence volume |
| CloudFront | Minimal | Request volume + data transfer |
| ElastiCache | Small fixed | Redis instance running 24/7 |
| Route 53 | ~$0.50/zone/month | DNS hosting |
| GitHub Actions | ~$15-25/month | CI/CD pipeline minutes |
The big insight: RDS and ECS are fixed costs (running 24/7 whether anyone uses the app or not). Bedrock is the primary variable cost that scales with usage. This cost structure is favorable for a SaaS model — your per-user marginal cost is mostly just the AI calls.
This document covers the system as of February 2026. CC and Claude maintain the infrastructure — this reference is for Joe to understand what they're working with and make informed decisions about the product.