AWS Technical Specification

Document ID: VDC-FS-001Version: 1.0Date: February 1, 2026Effective Date: February 1, 2026Status: Approved

1. Introduction

1.1 Purpose

This Functional Specification (FS) describes the technical design and implementation of the Validated Document Control (VDC) system. It details how each User Requirement (URS) is satisfied through system architecture, AWS services, and application logic.

1.2 Scope

This document covers:

  • System architecture and AWS service integration
  • Frontend application design (Next.js)
  • Backend API design (AWS Lambda functions)
  • Data models and storage (S3, DynamoDB)
  • Authentication and authorization (Cognito)
  • Security controls and encryption
  • Audit trail implementation

1.3 Related Documents

2. System Architecture

2.1 High-Level Architecture

The VDC system follows a serverless, event-driven architecture on AWS:

Presentation Layer
Next.js 16.1.1 (Static Export)
React 19.0.0
CloudFront CDN
Authentication Layer
Amazon Cognito User Pool
Cognito Hosted UI
MFA (TOTP)
API Layer
API Gateway (HTTP APIs)
8 Lambda Functions
JWT Authorizer
Data Layer
S3 (Documents)
DynamoDB (Metadata)
DynamoDB (Audit)

2.2 AWS Services Used

Service
Purpose
URS Mapping
Amazon S3
Document storage with versioning and encryption (SSE-S3)
URS-005, URS-023, URS-043
Amazon DynamoDB
Document metadata and immutable audit trail storage
URS-033, URS-034
AWS Lambda
Serverless compute for API endpoints (8 functions)
All workflow requirements
API Gateway
HTTP API with JWT authorization and CORS
URS-023
Amazon Cognito
User authentication with MFA enforcement and RBAC
URS-020, URS-021, URS-022
CloudWatch Logs
System monitoring and debugging logs
System observability
CloudFront
Global CDN with TLS 1.2+ enforcement
URS-023
AWS IAM
Fine-grained access control and least privilege
URS-021, URS-022

3. Frontend Application Design

3.1 Technology Stack

  • Framework: Next.js 16.1.1 with static export (SSG)
  • UI Library: React 19.0.0
  • Language: JavaScript (ES2022)
  • Styling: CSS-in-JS (styled-jsx)
  • Deployment: S3 static hosting + CloudFront

3.2 Page Structure

Application Pages
/life-sciences/app/
  ├── login.js              # Cognito Hosted UI redirect handler
  ├── index.js              # Role selection (Submitter / Approver)
  ├── upload.js             # Document upload interface (Submitter)
  ├── submissions.js        # Submitted documents list (Submitter)
  ├── documents/
  │   ├── index.js          # All documents list
  │   └── [id].js           # Document detail + audit trail
  └── approval/
      ├── index.js          # Approval workflow hub
      ├── approvals/
      │   └── index.js      # Pending approvals list (Approver)
      └── [id].js           # Approval review page (Approver)

3.3 Authentication Flow

  1. User navigates to /life-sciences/app/login
  2. System redirects to Cognito Hosted UI
  3. User enters email/password, completes MFA challenge (TOTP)
  4. Cognito redirects back with authorization code
  5. Frontend exchanges code for JWT tokens (ID token, Access token)
  6. Tokens stored in sessionStorage (cleared on browser close)
  7. All API calls include Authorization: Bearer <token>

4. Backend API Design

4.1 Lambda Functions

Function Name
HTTP Method
Purpose
URS
upload-init
POST
Generate pre-signed S3 URL for document upload
URS-001
submit
POST
Record document submission with metadata + audit
URS-002, URS-003, URS-004, URS-030
documents-list
GET
Retrieve document list (filtered by role)
URS-010, URS-011
download
GET
Generate pre-signed URL for document download
URS-012
approve
POST
Approve document + create audit record
URS-013, URS-014, URS-031
reject
POST
Reject document + create audit record
URS-013, URS-014, URS-031
document-audit
GET
Retrieve complete audit trail for a document
URS-034
approvals-pending
GET
List documents pending approval
URS-010

4.2 API Authorization

All API endpoints validate JWT tokens:

Authorization Flow
1. API Gateway receives request with Authorization header
2. JWT Authorizer validates token signature against Cognito JWKS
3. Authorizer extracts user claims: sub, email, cognito:groups
4. Lambda receives validated event.requestContext.authorizer.claims
5. Lambda enforces role-based access (Submitter / Approver)

4.3 Error Handling

All Lambda functions return standardized error responses:

{
  "statusCode": 400 | 401 | 403 | 500,
  "body": {
    "error": "Error message for client display",
    "details": "Additional context (dev/qa only)"
  }
}

5. Data Models

5.1 DynamoDB - Documents Table

Table: vdc-documents-dev
{
  "documentId": "doc_1234567890",           // Partition Key (PK)
  "filename": "protocol_v2.pdf",
  "submittedBy": "user@example.com",
  "submittedAt": "2025-01-10T14:32:18Z",    // ISO 8601 UTC
  "fileHash": "sha256:abc123...",           // SHA-256 integrity hash
  "status": "pending | approved | rejected",
  "s3Key": "documents/doc_1234567890.pdf",
  "approvedBy": "approver@example.com",     // If approved
  "approvedAt": "2025-01-10T15:45:22Z",     // If approved
  "rejectedBy": "approver@example.com",     // If rejected
  "rejectedAt": "2025-01-10T16:12:05Z"      // If rejected
}

5.2 DynamoDB - Audit Table

Table: vdc-audit-dev
{
  "auditId": "audit_1234567890",           // Partition Key (PK)
  "documentId": "doc_1234567890",          // GSI for querying by document
  "timestamp": "2025-01-10T14:32:18Z",     // Sort Key (SK) - ISO 8601
  "action": "SUBMIT | APPROVE | REJECT | DOWNLOAD",
  "userId": "user@example.com",            // Cognito sub claim
  "userEmail": "user@example.com",
  "ipAddress": "203.0.113.42",             // Source IP
  "userAgent": "Mozilla/5.0...",
  "outcome": "success | failure",
  "details": {                              // Action-specific metadata
    "filename": "protocol_v2.pdf",
    "fileHash": "sha256:abc123..."
  }
}

Immutability: IAM policies deny dynamodb:DeleteItem and dynamodb:UpdateItem on audit table. Only PutItem and Query allowed.

5.3 S3 - Document Storage

Bucket: vdc-documents-dev
Configuration:
  - Versioning: Enabled
  - Encryption: SSE-S3 (AES-256)
  - Public Access: Blocked
  - Lifecycle: Retain all versions (no deletion)
  
Object Key Format:
  documents/{documentId}.{extension}
  
Example:
  documents/doc_1234567890.pdf

6. Security Implementation

6.1 Encryption

Layer
Implementation
URS
Data in Transit
TLS 1.2+ enforced on CloudFront and API Gateway
URS-023
Data at Rest (S3)
SSE-S3 (AES-256) automatic encryption
URS-023
Data at Rest (DynamoDB)
AWS-managed encryption at rest
URS-023

6.2 Role-Based Access Control (RBAC)

Cognito groups enforce role separation:

Submitter Group:
  - Can: Upload documents, view own submissions
  - Cannot: Approve/reject any documents
  
Approver Group:
  - Can: View pending approvals, approve/reject documents
  - Cannot: Approve own submissions (enforced in Lambda)
  
Implementation:
  - Cognito group membership in JWT token
  - Lambda checks cognito:groups claim
  - Self-approval prevented: submittedBy !== currentUser

6.3 IAM Least Privilege

Each Lambda function has minimal IAM permissions:

  • upload-init: s3:PutObject only
  • submit: dynamodb:PutItem (documents + audit tables)
  • approve/reject: dynamodb:UpdateItem (documents), PutItem (audit)
  • download: s3:GetObject with pre-signed URL (5 min expiry)
  • All: logs:CreateLogStream, logs:PutLogEvents

7. Audit Trail Implementation

7.1 Audit Event Capture

Every significant action triggers audit log creation:

async function createAuditLog(event) {
  const auditRecord = {
    auditId: generateId('audit'),
    documentId: event.documentId,
    timestamp: new Date().toISOString(),
    action: event.action,                // SUBMIT, APPROVE, REJECT, DOWNLOAD
    userId: event.userContext.sub,
    userEmail: event.userContext.email,
    ipAddress: event.requestContext.http.sourceIp,
    userAgent: event.requestContext.http.userAgent,
    outcome: 'success',
    details: event.details
  };
  
  await dynamodb.put({
    TableName: 'vdc-audit-dev',
    Item: auditRecord
  });
}

7.2 Audit Trail Retrieval

The document-audit Lambda function queries audit logs by documentId GSI:

GET /api/documents/{documentId}/audit

Response:
{
  "documentId": "doc_1234567890",
  "auditTrail": [
    {
      "timestamp": "2025-01-10T14:32:18Z",
      "action": "SUBMIT",
      "userId": "submitter@example.com",
      "details": { "filename": "protocol_v2.pdf", "hash": "sha256:..." }
    },
    {
      "timestamp": "2025-01-10T15:45:22Z",
      "action": "APPROVE",
      "userId": "approver@example.com",
      "ipAddress": "203.0.113.42"
    }
  ]
}

7.3 ALCOA+ Compliance

Principle
Implementation
URS
Attributable
Cognito sub + email in every audit record
URS-040
Legible
UTF-8 encoded, human-readable JSON
URS-041
Contemporaneous
ISO 8601 timestamp captured at action time
URS-042
Original
S3 versioning preserves original uploads
URS-043
Accurate
SHA-256 hash verification on submit
URS-044

8. Deployment Architecture

8.1 Infrastructure as Code

All AWS resources deployed via CloudFormation:

  • cloudformation/vdc-infrastructure.yaml - S3, DynamoDB, Cognito, IAM
  • cloudformation/vdc-api.yaml - API Gateway, Lambda functions
  • Stack naming: vdc-{env} where env = dev | prod

8.2 Environment Separation

Environment
Purpose
Resources
DEV
Development and testing (validated)
Separate S3, DynamoDB, Cognito, API Gateway
PROD
Production demo (publicly accessible)
Separate S3, DynamoDB, Cognito, API Gateway

8.3 Deployment Process

  1. Build Next.js static export: npm run build
  2. Deploy CloudFormation stacks (infrastructure + API)
  3. Deploy Lambda function code via CloudFormation
  4. Upload static files to S3
  5. Invalidate CloudFront cache
  6. Execute smoke tests (IQ protocol)

9. Monitoring & Observability

9.1 CloudWatch Logs

  • All Lambda functions log to CloudWatch Logs
  • Log retention: 30 days
  • Log format: JSON structured logs with timestamp, level, message

9.2 Metrics

  • Lambda invocation count, duration, errors (automatic)
  • API Gateway request count, latency, 4xx/5xx errors
  • DynamoDB consumed read/write capacity units

10. Testing Strategy

See IQ/OQ/PQ Results for detailed test execution evidence.

10.1 Installation Qualification (IQ)

  • Verify AWS resource creation via CloudFormation
  • Confirm encryption settings (S3, DynamoDB)
  • Validate IAM policies and least privilege
  • Verify network configuration (VPC, security groups - N/A for serverless)

10.2 Operational Qualification (OQ)

  • Test all Lambda functions independently
  • Verify API Gateway authorization
  • Test error handling and edge cases
  • Validate audit log creation

10.3 Performance Qualification (PQ)

  • End-to-end workflow testing (Submitter → Approver)
  • Role-based access validation
  • Audit trail completeness verification
  • Data integrity testing (hash verification)

11. Approval

System Architect
William O''Connell
February 1, 2026
Quality Assurance
William O''Connell
February 1, 2026