Deployment Architecture
Deployment Architecture
Project:
Drop{{PROJECT_NAME}} Version:0.1.0{{VERSION}} Date:2026-02-23{{DATE}} Author:Platform Architect (AI){{AUTHOR}} Status: Draft | In Review | Approved Reviewers:Alem Bašić (CEO){{REVIEWERS}}
Document History
| Version | Date | Author | Changes |
|---|---|---|---|
| 0.1 | Initial draft |
1. Overview
Drop is a remittance and QR payment application deployed on AWS in the eu-west-1 (Ireland) region. The application uses a Next.js 16 standalone server containerised in a multi-stage Docker image and served via AWS App Runner. The database is RDS PostgreSQL (db.t4g.micro) with automated daily snapshots and 7-day retention. All infrastructure is production-grade; staging runs on Fly.io (Stockholm).
System: Drop — Remittance + QR Payment App{{PROJECT_NAME}}
Cloud Provider: AWS{{CLOUD_PROVIDER}} (production), Fly.io (staging)
Provider Rationale: AWS{{RATIONALE}} App Runner chosen for fully managed container hosting with zero infrastructure management; auto-scaling built-in; GDPR data residency satisfied by eu-west-1 (Ireland).
Architecture Pattern: Monolith{{PATTERN}} — single Next.js app serving both frontend and API routes.
2. Infrastructure Topology
graph TB
subgraph Internet
USER[End UsersUsers]
CDN[CDN / Mobile App]
BSTACK[BetterStack Uptime Monitor]CloudFront]
end
subgraph AWSPublic eu-west-1Subnet
subgraphALB[Application AppLoad RunnerBalancer]
AR[AWSBASTION[Bastion App Runner\ndrop-web\neu-west-1]Host]
end
subgraph ECRPrivate REPO[ECRSubnet Repository\n324480209768.dkr.ecr.eu-west-1\n.amazonaws.com/drop-web]- App
APP1[App Server 1]
APP2[App Server 2]
end
subgraph RDSPrivate DB[Subnet - Data
DB_PRIMARY[(RDSPrimary PostgreSQLDB)]
16\ndrop-db\ndb.t4g.micro\ndrop-db.czu2qe4quy4v\n.eu-west-1.rds.amazonaws.com)DB_REPLICA[(Read Replica)]
CACHE[Redis Cache]
end
subgraph Isolated Subnet
SECRETS[Secrets SM[AWSManager]
SecretsBACKUP[Backup Manager\nJWT_SECRET\nDATABASE_URL\nSLACK_WEBHOOK_URL]
end
subgraph CloudWatch
LOGS[CloudWatch Logs\n/aws/apprunner/drop-web/...]
end
end
subgraph Staging - Fly.io Stockholm
FLY[Fly.io App\ndrop-staging\nSQLite ephemeral]
end
subgraph External Services
SUMSUB[Sumsub KYC API\napi.sumsub.com]
BANKID[BankID OIDC\nNorwegian eID]
SLACK[Slack Webhook\nalai-talk.slack.com]Storage]
end
USER --> ARCDN
BSTACKCDN --> ARALB
ARALB --> DBAPP1
ARALB --> SMAPP2
ARAPP1 --> LOGSDB_PRIMARY
ARAPP2 --> SUMSUBDB_PRIMARY
ARAPP1 --> BANKIDCACHE
ARDB_PRIMARY --> SLACKDB_REPLICA
REPOAPP1 --> ARSECRETS
3. Networking Architecture
3.1 VPC / VNET Design
App Runner is a fully managed service — AWS manages the underlying VPC. Drop's RDS instance is in the default VPC in eu-west-1. No custom CIDR ranges are managed by Drop at this stage.
| Network | CIDR | Purpose |
|---|---|---|
| Public Subnet B | {{CIDR_PUB_B}} | Load balancers, NAT gateways (AZ-B) |
| Private Subnet A | {{CIDR_PRIV_A}} | Application servers |
| Private Subnet B | {{CIDR_PRIV_B}} | Application servers (AZ-B) |
| Isolated Subnet A | {{CIDR_ISO_A}} | Databases, secrets |
| Isolated Subnet B | {{CIDR_ISO_B}} | Databases, secrets (AZ-B) |
Note: Custom VPC with private subnets is tracked as a security hardening item for v1.0 production launch.
3.2 Load Balancer Configuration
App Runner provides a built-in HTTPS load balancer — no ALB/NLB managed by Drop.
| Parameter | Value |
|---|---|
| Type | |
| Protocol | HTTPS (TLS 1.2+) |
| SSL Termination | At |
| Health Check Path | {{HEALTH_CHECK_PATH}} |
| Health Check Interval | |
| Unhealthy Threshold | |
| Stickiness | {{STICKINESS}} |
3.3 DNS Architecture
| Record | Type | Value | TTL |
|---|---|---|---|
| A / ALIAS | |||
API Load Balancer |
|||
| cdn.{{DOMAIN}} | CNAME | CDN Distribution | {{TTL}} |
DNS Provider: TBD — requires domain transfer from getdrop.no registration (drop.no owned by TV2).{{DNS_PROVIDER}}
Failover Strategy: Manual{{FAILOVER_STRATEGY}} failover via DNS update to secondary App Runner service in eu-north-1.
3.4 CDN Configuration
| Parameter | Value |
|---|---|
| Provider | |
| Cache |
Static |
| HTTPS Only | Yes |
| WAF Integration |
Note: CDN and WAF integration planned for v1.0 launch via CloudFront + AWS WAF.
4. Compute
4.1 Container Orchestration
Platform: AWS{{ORCHESTRATION}} App Runner (managed container service — no cluster management)
| Component | Configuration | Notes |
|---|---|---|
{{CLUSTER_SPEC}} |
||
| Node Groups | {{NODE_GROUPS}} | |
| Min Nodes | {{MIN_NODES}} | |
| Max Nodes | {{MAX_NODES}} | |
| Node Size | {{NODE_SIZE}} | |
| Container Registry | {{REGISTRY}} |
|
| ||
| ||
| ||
|
4.2 Serverless Functions
No
serverless
| Function | Trigger | Memory | Timeout | Purpose |
|---|---|---|---|---|
| {{FUNCTION_1}} | {{TRIGGER}} | {{MEMORY}}MB | {{TIMEOUT}}s | {{PURPOSE}} |
4.3 Instance Sizing & Auto-Scaling
| Service | Min | Max | Scale Trigger | |
|---|---|---|---|---|
AppScale-Out Runner Auto-Scaling:Policy: Managed{{SCALE_OUT}} by
minimumScale-In inPolicy: production,{{SCALE_IN}} scale-to-zero
inScale-In stagingCooldown: (Fly.io).{{COOLDOWN}}min
5. Storage
5.1 Database Hosting
| Database | Engine | Version | Hosting | Instance | Storage | HA |
|---|---|---|---|---|---|---|
Connection Pooling: Application-level{{POOL_TOOL}} (no PgBouncer currently)
Max Connections: Default RDS db.t4g.micro (~85 connections){{MAX_CONN}}
Connection String: Stored in AWS Secrets Manager{{SECRET_LOCATION}} (DATABASE_URL); never hardcoded.
DB Endpoint: drop-db.czu2qe4quy4v.eu-west-1.rds.amazonaws.com:5432
DB Name: dropapp
DB User: hardcoded)dropuser
5.2 Object Storage
No
S3
| Bucket |
Purpose | Access | Lifecycle | Encryption |
|---|---|---|---|---|
| {{BUCKET_NAME}} | {{PURPOSE}} | {{ACCESS}} | {{LIFECYCLE}} | AES-256 |
5.3 File Storage
| Storage | Type | Mount Point | Purpose | Size |
|---|---|---|---|---|
{{MOUNT}} |
6. Security
6.1 Network Security Groups / Firewall Rules
| Security Group | Direction | Port | Protocol | Source / Destination | Purpose |
|---|---|---|---|---|---|
| Inbound | 443 | TCP | 0.0.0.0/0 | HTTPS from internet | |
| Outbound | TCP | ||||
| sg-app | Inbound | {{APP_PORT}} | TCP | sg-alb | From load balancer |
| sg-app | Outbound | {{DB_PORT}} | TCP | sg-db | Database access |
| TCP |
6.2 WAF Configuration
WAF Provider: None currently (planned for v1.0 via CloudFront + AWS WAF)
Planned rules:{{WAF_PROVIDER}}
| Rule Group | Purpose | Action |
|---|---|---|
| AWSManagedRulesCommonRuleSet | OWASP Top 10 | Block |
| AWSManagedRulesSQLiRuleSet | SQL injection | Block |
| AWSManagedRulesKnownBadInputsRuleSet | Known bad inputs | Block |
| Rate limiting | Count → Block |
Current mitigation: Application-level rate limiting in middleware.ts using rate_limits DB table (10 req/min on auth endpoints, 120 req/min on public rate endpoints).
6.3 Secrets Management
Secret Store: AWS{{SECRET_STORE}} Secrets Manager (auto-detected via AWS_SECRET_ARN env var) with fallback to environment variables.
| Secret | Rotation Schedule | Access |
|---|---|---|
Database |
90 days | App |
| API ||
(third-party) |
On compromise | App |
| ||
| ||
| TLS certificates | ||
| JWT signing key | 365 days | Auth service only |
Caching: Secrets cached in-memory for 5 minutes (configurable TTL via initSecrets()).
6.4 IAM Roles & Policies
| Role | Trusted By | Key Permissions | Purpose | ||
|---|---|---|---|---|---|
S3:GetObject |
Application runtime | ||||
{{DEPLOY_ROLE}} |
CI/CD | ECR:PushImage, ECS:UpdateService | Deployments | ||
Lambda / Cron |
|
7. Cost Estimation
| Component | Service | Spec | Est. Monthly Cost |
|---|---|---|---|
| Compute | |||
| Database | |||
| ${{COST}} | |||
| CDN | {{SERVICE}} | {{TRAFFIC}}GB transfer | $ |
| Storage | {{SERVICE}} | {{CAPACITY}}GB | |
| Monitoring | |||
| $ |
|||
| Total |
Cost Optimization Notes:
AppRunnerscales to minimum instances in off-peak; staging (Fly.io) scales to zero.db.t4g.microisARM-based Graviton — 20% cheaper than equivalent x86 instance.Reserved instance / savings plan upgrade planned at v1.0 launch.
8. High Availability Design
| Component | HA Strategy | Failover Time | Notes | ||
|---|---|---|---|---|---|
| Application |
Immediate (ELB health |
||||
| Database | Multi-AZ |
60-120 seconds | DNS propagation | ||
RTO Target: 10{{RTO}} minutes (App Runner restart) / 30 minutes (RDS restore)
RPO Target: 5{{RPO}} minutes (RDS PITR) / 24 hours (daily snapshot)
9. Multi-Region Considerations
Current: Single-region{{REGION_STRATEGY}} (eu-west-1 Ireland)
Primary Region: eu-west-1 (Ireland){{PRIMARY_REGION}}
Secondary Region: eu-north-1{{SECONDARY_REGION}} (Stockholm) — manual failover target only
Rationale: Single-region{{MULTI_REGION_RATIONALE}}
Data Replication: None{{REPLICATION_STRATEGY}} (manual snapshot copy to eu-north-1 on region failover)
Failover Procedure: See disaster-recovery-plan.md
10. Related Documents
- CI/CD Pipeline
- Environment Configuration
- Infrastructure as Code
- Monitoring & Observability
- Disaster Recovery Plan
Approval
| Role | Name | Date | Signature |
|---|---|---|---|
| Author | |||
| Reviewer | |||
| Approver |