Skip to main content

Architecture Reference

CC reads this on demand. For rules and workflow, see CLAUDE.md.

Project Overview

Nquiry (codebase: nquir) — A Next.js application for managing compliance-critical work including investigations, evaluations, audits, reviews, and assessments. Users can create projects, upload evidence, define investigation topics, generate AI-powered analysis, and create professional reports.

Tech Stack

  • Framework: Next.js 16 (App Router) with React 19
  • Database: Amazon RDS PostgreSQL
  • Authentication: Amazon Cognito
  • File Storage: Amazon S3 (server-side encryption, signed URLs)
  • Hosting: AWS ECS Fargate (Next.js standalone) behind CloudFront + ALB, CI/CD via GitHub Actions → ECR → ECS
  • Styling: Tailwind CSS + shadcn/ui
  • AI: AWS Bedrock (Claude via @anthropic-ai/bedrock-sdk)
  • Infrastructure: Terraform configs in infrastructure/terraform/
  • Runtime: Node.js 24

Multi-Tenant Architecture

Every user belongs to at least one organization:

  • Personal orgs: Auto-created on signup, type='personal', slug personal-{user_id}
  • Team orgs: Created manually, type='team'
  • Investigations belong to organizations, not directly to users
  • User roles: owner > admin > member > viewer

Key tables: organization, organization_member, organization_invitation, investigation

Application-layer authorization (RLS is dead code — see lib/db/client/server.ts):

  • hasOrgRole(orgId, minRole) in lib/organization/index.ts — API routes
  • verifyInvestigationAccess(investigationId) in lib/investigation/access.ts — server actions
  • createProtectedRoute({ requiredRole, organizationId }) in lib/api/route-wrapper.ts — route wrapper

Storage Paths

{organization_id}/{investigation_id}/{evidence_id}/{filename}

Buckets: evidence, evaluation-guides, framework-documents


API Route Requirements

Every API route MUST have:

  1. Authentication check — Return 401 if !user
  2. Organization authorization — Verify user has access via hasOrgRole()
  3. Input validation — Check required fields, types, bounds
  4. Error handling — try/catch with specific error messages
  5. Audit logging — Log state changes (success AND failure)
  6. Tests — Route must have corresponding test coverage

Use createProtectedRoute from lib/api/route-wrapper.ts — it handles auth, rate limiting, org context, and error handling automatically.

Before creating any new route, ask:

  • What could a malicious authenticated user do with this endpoint?
  • Is organization membership verified before accessing resources?
  • Are failures logged to the audit trail?

Common Patterns

Organization access:

import { hasOrgRole, getCurrentOrganization } from "@/lib/organization";

const currentOrg = await getCurrentOrganization();
const canEdit = await hasOrgRole(currentOrg.organization_id, "member");

Filtering queries by organization:

const { data } = await supabase
.from("investigation")
.select("*")
.eq("organization_id", currentOrg.organization_id);

Audit logging:

import {
auditInvestigation,
auditEvidence,
auditAnalysis,
logFailure,
} from "@/lib/audit";

await auditInvestigation.create(investigationId, orgId, title);
await auditEvidence.create(evidenceId, orgId, title, investigationId);
await auditAnalysis.generate(investigationId, orgId, "comprehensive");
await logFailure(
"investigation.update",
"investigation",
"Permission denied",
investigationId,
);

Audit logs include: user, organization, timestamp, action, resource, IP, user agent, success/failure, metadata.


AI Quality & Metrics

Nquiry's value depends on AI accuracy and reliability. Every AI output must be traceable.

For any analysis, we must be able to answer:

  • Which prompt version produced this?analysis.prompt_id + analysis.prompt_version
  • Did the output pass validation?analysis.validation_passed + analysis.validation_errors
  • What evidence was retrieved?analysis_evidence_retrieval table
  • What were the similarity scores? → Logged in retrieval metadata

When Building AI Features

  1. Log the execution — Record prompt version, input context, validation result, latency
  2. Track the outcome — Did user accept, edit, or reject the output?
  3. Link the chain — Prompt → Execution → Output → User Action → Finding

Quality Metrics

MetricQuestionImplementation
Validation pass rateOutput match expected schema?analysis.validation_passed
Retrieval qualityRelevant evidence found?Similarity scores in retrieval log
Prompt version performanceIs version N better than N-1?Aggregate by prompt_version
User acceptance rateDo users trust the output?Track edits/regenerations

Key AI Files

FilePurpose
lib/ai/analysis-output-validators.tsZod schemas for validating AI output
lib/ai/analysis-output-schema.tsTypeScript types for structured output
app/api/analysis/generate/route.tsAnalysis generation with prompt tracking
prompt_template + prompt_template_historyPrompt versioning and rollback

See docs/claude_ai_work/research/rag-quality-metrics-research.md for RAG evaluation framework.


Key Files

FilePurpose
lib/organization/index.tsOrganization utilities (getCurrentOrganization, hasOrgRole)
lib/db/client/server.tsServer database client
lib/db/client/client.tsBrowser database client
lib/billing/plans.tsBilling tiers (trial, professional, team, enterprise)
lib/billing/trial.tsTrial status checks and logic
lib/audit/index.tsAudit logging utilities
app/(auth)/actions.tsAuth actions (signup creates personal org)
components/organization-switcher.tsxOrg dropdown in header

Communication Standards

Confidence Levels:

  • "Based on [service] documentation..." = Verified from official docs
  • "In my experience with similar [services/patterns]..." = Pattern recognition, not verified
  • "This is typically how [concept] works..." = General knowledge, verify if high-stakes

For high-stakes decisions (production changes, compliance):

  1. Search official documentation FIRST
  2. Present options with explicit confidence: "I'm certain" / "This is likely" / "I'm unsure, let me search"
  3. For AWS/federal applications, verify against official requirements before advising
  4. If something "should work" but doesn't, stop and research

Environment Variables

See .env.example for required variables. Copy to .env.local and fill in values.


Testing & CI/CD

npm run test # All tests
npm run test:unit # Unit only
npm run test:integration # Integration only
npm run test:watch # Watch mode

Test locations: __tests__/unit/, __tests__/integration/, __tests__/e2e/

CI/CD (.github/workflows/ci.yml): lint → type-check → build → test. Runs on push to main and PRs.