AWS Technical Specification
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:
2.2 AWS Services Used
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
/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
- User navigates to
/life-sciences/app/login - System redirects to Cognito Hosted UI
- User enters email/password, completes MFA challenge (TOTP)
- Cognito redirects back with authorization code
- Frontend exchanges code for JWT tokens (ID token, Access token)
- Tokens stored in sessionStorage (cleared on browser close)
- All API calls include
Authorization: Bearer <token>
4. Backend API Design
4.1 Lambda Functions
upload-initsubmitdocuments-listdownloadapproverejectdocument-auditapprovals-pending4.2 API Authorization
All API endpoints validate JWT tokens:
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
{
"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
{
"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
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.pdf6. Security Implementation
6.1 Encryption
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:PutObjectonlysubmit:dynamodb:PutItem(documents + audit tables)approve/reject:dynamodb:UpdateItem(documents),PutItem(audit)download:s3:GetObjectwith 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
8. Deployment Architecture
8.1 Infrastructure as Code
All AWS resources deployed via CloudFormation:
cloudformation/vdc-infrastructure.yaml- S3, DynamoDB, Cognito, IAMcloudformation/vdc-api.yaml- API Gateway, Lambda functions- Stack naming:
vdc-{env}where env = dev | prod
8.2 Environment Separation
8.3 Deployment Process
- Build Next.js static export:
npm run build - Deploy CloudFormation stacks (infrastructure + API)
- Deploy Lambda function code via CloudFormation
- Upload static files to S3
- Invalidate CloudFront cache
- 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)