Flagship project
Engineering reference project

Answers you can trace to a record

A retrieval-grounded generative assistant over private data on AWS. The engineering is in the retrieval, isolation and delivery layer, not the model.

Discuss a similar build
Fortis engineering reference project. Built and operated by Fortis as a working reference implementation, not delivered under contract to a client. No customer, program or employer material appears here. Figures describe measured behaviour of this build only.
Type
Engineering reference build
Primary platform
AWS, single region
Pattern
Retrieval-grounded generation
Status
Built, run, then migrated on-premises

Executive overview

A generative assistant that answers questions about an organisation's own data, built so that every answer can be traced to the record it came from. The engineering problem is not the model. It is the retrieval, isolation, validation and delivery layer that decides whether an answer is trustworthy.

Application compute, an in-memory cache and a managed PostgreSQL instance sit inside a private subnet. Everything else, including inference, retrieval, document extraction and image analysis, is a managed service reached by API under narrowly scoped IAM roles. Infrastructure is declared in Terraform and delivery runs through a pipeline rather than by hand.

It was later migrated to an on-premises platform, which is itself the useful part: the same architecture was proven twice, once managed and once self-hosted, with the data verified across the move.

The problem

Organisations hold the data that would make an assistant useful, and cannot put it behind one.

Problem

Three reasons recur, and none of them are about model quality.

  • Provenance. A model that answers from training recall cannot show a source. In a regulated environment an answer without provenance is not an answer, it is a liability.
  • Exposure. Wiring a language model to a production database usually means giving something broad, credentialed access to records nobody intended to expose.
  • Cost and latency. Naive retrieval hits the database on every request for data that has not changed, which is slow and expensive at the same time.

The requirement was an assistant that grounds answers in private records, reaches those records through a narrow and auditable path, and does so fast enough to be used rather than tolerated.

Engineering approach

Retrieval runs before inference, not after. The model receives private context as input rather than being asked to recall it. That single ordering decision is what makes an answer traceable, and it shapes everything else in the architecture.

  • Application compute orchestrates the request and holds no long-lived credentials of its own, assuming a scoped role instead.
  • The cache absorbs repetitive reads. On a miss, a parameterised query reaches the relational store and the result is written back with a bounded lifetime.
  • Document extraction converts physical documents into structured relational records, with image analysis returning confidence scores rather than bare assertions.
  • Document metadata is stored separately from the relational record, keyed on record identity, which is what makes repeated writes idempotent.
  • Terraform declares the infrastructure. The pipeline builds and deploys on push, so a commit and a running instance never diverge.

Architecture

Two views. The first is the shape a client needs in order to understand the trust boundary. The second is the engineering view, including identity, delivery and provisioning.

Enlarge Client reference architecture for the GenAI data assistant on AWS
Figure 1Client reference architecture. Only the compute instance, the cache and the relational database sit inside the VPC. Inference, retrieval, extraction, image analysis, object storage and the metadata table are managed services reached by API. The consequence worth naming: the network boundary alone does not protect those services, so the control that matters is the IAM role scope, not the subnet.
Enlarge Engineering architecture including identity, CI/CD and provisioning
Figure 2Engineering architecture. Adds agent orchestration, scoped IAM roles, the build and deploy chain, the event-driven voice path, analytics, and Terraform provisioning. The pipeline deploys into the private subnet; it does not reach in from outside.

Key technologies

Inference and retrieval
  • Amazon Bedrock
  • Bedrock Agents
  • Bedrock Knowledge Bases
  • OpenSearch Serverless
Data and caching
  • RDS for PostgreSQL
  • ElastiCache for Redis, cache-aside
  • DynamoDB for metadata
  • Amazon S3 as knowledge source
Document intelligence
  • Amazon Textract
  • Amazon Rekognition
  • Metadata keyed on record identity
Platform and network
  • VPC with private subnet
  • IAM-scoped roles, no static keys
  • Managed services reached by API
Automation
  • Terraform
  • CodePipeline, CodeBuild, CodeDeploy
  • AWS Lambda for the voice path
Languages
  • Python and boto3
  • SQL
  • HCL

Security and operational considerations

  • The subnet is not the control. Most services here sit outside the VPC by design. What limits blast radius is that each role is scoped to the specific resources it needs, so a compromised component reaches that component's data and nothing else.
  • No static credentials in application code. Compute assumes a role. Nothing in the repository is a working key.
  • Retrieval is read-only by design. The path that answers a question cannot write to the system of record.
  • Cost has an operational failure mode. A serverless vector collection continues to bill whether or not anything queries it. It is inventoried deliberately rather than discovered on an invoice, and the same discipline applies to unattached addresses and orphaned volumes.
  • Confidence scores are surfaced, not hidden. Image analysis returns a score, and the consuming code treats a low score as a low score rather than a fact.
Decisions

The alternatives that were rejected, and why. This is the part that shows judgement.

Important engineering decisions

Retrieval before inference

Alternative rejected: prompting the model to answer from its own training

Grounding responses in retrieved private context is what makes an answer auditable. Asking a model to recall an organisation's data produces fluent text with no provenance, which is worse than no answer because it is harder to catch.

Cache-aside rather than write-through

Alternative rejected: write-through caching, or scaling the database

The access pattern was heavily repetitive: the same records fetched across many requests. Cache-aside puts the fix where the repetition is. Write-through would have added consistency burden for no benefit at this read-to-write ratio, and scaling the database would have paid money to solve a problem that was not about capacity.

Metadata keyed on record identity

Alternative rejected: keying on the write event

The original key design meant a retried write created a duplicate record. Re-keying around the identity of the thing being described made writes idempotent and removed that class of duplicate entirely, rather than adding reconciliation to clean up after it.

Only stateful components inside the VPC

Alternative rejected: forcing every service behind private endpoints

Private endpoints for every managed service would have added cost and configuration for a marginal gain, given that the real control is IAM role scope. The boundary is drawn around the components that hold state, and the decision is documented so that it reads as a choice rather than an omission.

Infrastructure declared, not clicked

Alternative rejected: console-created resources

A resource created in a console cannot be reproduced, reviewed or reliably destroyed. The practical cost showed up at teardown: resources in Terraform state had to be destroyed through Terraform and console-created resources through the CLI, because deleting a managed resource out of band leaves state pointing at nothing.

What it does

Measured behaviour of this build, and the service lines it stands behind.

Demonstrated capabilities

Measured on this build. Nothing here is a client outcome or a contracted result.

  • Retrieval pipeline grounding responses in private records rather than model recall, with the source context available alongside the answer.
  • Cache-aside layer delivering roughly thirty times faster reads than the direct database path on the repetitive access pattern this workload actually has.
  • Document extraction pipeline converting unstructured documents into structured relational records.
  • Image analysis returning confidence scores that the consuming code acts on.
  • Key redesign that made writes idempotent, eliminating duplicate records created by retries.
  • Automated delivery from commit to a running instance in under two minutes.
  • Full migration off managed cloud onto a self-hosted platform with row counts reconciled against pre-migration figures, proving the architecture twice.
  • Architecture and decision record documented, including the alternatives rejected.

What this demonstrates

This project is the reference implementation behind two Fortis service lines.

AI and GenAI Data Engineering

Retrieval-augmented generation over private datasets, document intelligence, and the data pipelines behind them. The pattern here is the one Fortis proposes: retrieval first, read-only, provenance preserved.

Data Platform Engineering

Relational, caching and NoSQL components chosen by access pattern rather than habit, with the caching decision driven by measurement of the actual read profile.

Cloud Modernization

A complete AWS footprint declared in code, delivered through a pipeline, and then migrated off with verification at every gate. Both directions of a modernization exercise.

Security posture

Least-privilege role scoping as the primary control, no static credentials in code, read-only retrieval paths, and cost exposure treated as an operational risk.