Skip to main content

Deployment Architecture

Deployment Architecture

Project: Drop Version: 0.1.0 Date: 2026-02-23 Author: Platform Architect (AI) Status: In Review Reviewers: Alem Bašić (CEO)

Document History

Version Date Author Changes
0.1 2026-02-23 Platform Architect (AI) Initial draft from source code analysis

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 Cloud Provider: AWS (production), Fly.io (staging) Provider Rationale: AWS 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 — single Next.js app serving both frontend and API routes.


2. Infrastructure Topology

graph TB
    subgraph Internet
        USER[End Users / Mobile App]
        BSTACK[BetterStack Uptime Monitor]
    end

    subgraph AWS eu-west-1
        subgraph App Runner
            AR[AWS App Runner\ndrop-web\neu-west-1]
        end

        subgraph ECR
            REPO[ECR Repository\n324480209768.dkr.ecr.eu-west-1\n.amazonaws.com/drop-web]
        end

        subgraph RDS
            DB[(RDS PostgreSQL 16\ndrop-db\ndb.t4g.micro\ndrop-db.czu2qe4quy4v\n.eu-west-1.rds.amazonaws.com)]
        end

        subgraph Secrets
            SM[AWS Secrets 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]
    end

    USER --> AR
    BSTACK --> AR
    AR --> DB
    AR --> SM
    AR --> LOGS
    AR --> SUMSUB
    AR --> BANKID
    AR --> SLACK
    REPO --> AR

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
AWS Default VPC (eu-west-1) AWS-managed App Runner + RDS default networking
App Runner Outbound AWS-managed NAT Egress to RDS, Sumsub, BankID APIs

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 AWS App Runner (built-in HTTPS proxy)
Protocol HTTPS (TLS 1.2+) — App Runner enforced
SSL Termination At App Runner edge
Health Check Path /api/health
Health Check Interval 30s
Unhealthy Threshold 3 consecutive failures
Force HTTPS true (Fly.io staging), App Runner default

3.3 DNS Architecture

Record Type Value TTL
getdrop.no (future) ALIAS App Runner URL 300
Current production 9ef3szvvsb.eu-west-1.awsapprunner.com App Runner managed

DNS Provider: TBD — requires domain transfer from getdrop.no registration (drop.no owned by TV2). Failover Strategy: Manual failover via DNS update to secondary App Runner service in eu-north-1.

3.4 CDN Configuration

Parameter Value
Provider None currently — App Runner serves directly
Static assets Served from Next.js .next/static/ via App Runner
WAF Integration TBD — requires domain + CloudFront setup

Note: CDN and WAF integration planned for v1.0 launch via CloudFront + AWS WAF.


4. Compute

4.1 Container Orchestration

Platform: AWS App Runner (managed container service — no cluster management)

Component Configuration Notes
Service ARN arn:aws:apprunner:eu-west-1:324480209768:service/drop-web/8e45b0d335304487a1880f4e32d6aeec Production
Container Registry ECR 324480209768.dkr.ecr.eu-west-1.amazonaws.com/drop-web
Service URL https://9ef3szvvsb.eu-west-1.awsapprunner.com Production
Base Image node:22-alpine Multi-stage build
Non-root user nextjs (UID 1001) Security hardened
Exposed Port 3000
Entrypoint node server.js Next.js standalone

4.2 Serverless Functions

No serverless functions currently. All logic is in Next.js API routes served by App Runner.

4.3 Instance Sizing & Auto-Scaling

Service Platform Min Max Scale Trigger
drop-web App Runner 1 Auto Managed by App Runner
drop-staging Fly.io 0 Auto Scales to zero when idle, auto-start on request

App Runner Auto-Scaling: Managed by AWS. Scales on concurrent request count. Default: 1 instance minimum in production, scale-to-zero in staging (Fly.io).


5. Storage

5.1 Database Hosting

Database Engine Version Hosting Instance Storage HA
drop-db (prod) PostgreSQL 16 AWS RDS db.t4g.micro TBD — requires RDS console check Single-AZ (multi-AZ upgrade planned)
drop-staging (staging) SQLite (better-sqlite3 12.6.2) Fly.io ephemeral volume No HA

Connection Pooling: Application-level (no PgBouncer currently) Max Connections: Default RDS db.t4g.micro (~85 connections) Connection String: Stored in AWS Secrets Manager (DATABASE_URL); never hardcoded. DB Endpoint: drop-db.czu2qe4quy4v.eu-west-1.rds.amazonaws.com:5432 DB Name: dropapp DB User: dropuser

5.2 Object Storage

No S3 buckets currently. Drop is a pass-through payment app — no user file uploads.

5.3 File Storage

Storage Type Mount Point Purpose Size
Fly.io Volume (staging) Persistent volume /app/data SQLite database + backups 1GB

6. Security

6.1 Network Security Groups / Firewall Rules

Security Group Direction Port Protocol Source / Destination Purpose
App Runner Inbound 443 TCP 0.0.0.0/0 HTTPS from internet
App Runner Outbound 5432 TCP RDS endpoint PostgreSQL access
App Runner Outbound 443 TCP 0.0.0.0/0 External APIs (Sumsub, BankID, Slack)

6.2 WAF Configuration

WAF Provider: None currently (planned for v1.0 via CloudFront + AWS WAF)

Planned rules:

Rule Group Purpose Action
AWSManagedRulesCommonRuleSet OWASP Top 10 Block
AWSManagedRulesSQLiRuleSet SQL injection Block
Rate limiting 100 req/5min per IP 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 Secrets Manager (auto-detected via AWS_SECRET_ARN env var) with fallback to environment variables.

Secret Rotation Schedule Access
DATABASE_URL (PostgreSQL credentials) 90 days App Runner role only
JWT_SECRET 90 days App Runner role only
SLACK_WEBHOOK_URL On compromise App Runner role only
BANKID_CLIENT_SECRET Per BankID policy App Runner role only
SUMSUB_API_KEY 180 days App Runner role only
TLS certificates Auto-renewed by App Runner AWS managed

Caching: Secrets cached in-memory for 5 minutes (configurable TTL via initSecrets()).

6.4 IAM Roles & Policies

Role Trusted By Key Permissions Purpose
App Runner task role AWS App Runner secretsmanager:GetSecretValue, ecr:GetAuthorizationToken Application runtime
GitHub Actions deploy role GitHub Actions (OIDC) apprunner:StartDeployment, ecr:PushImage, ecr:BatchCheckLayerAvailability CI/CD deployments
RDS monitoring role arn:aws:iam::324480209768:role/rds-monitoring-role rds:DescribeDBInstances, CloudWatch metrics RDS enhanced monitoring

7. Cost Estimation

Component Service Spec Est. Monthly Cost
Compute AWS App Runner 0.25 vCPU / 0.5GB (auto-scale) ~$25–50
Database AWS RDS PostgreSQL db.t4g.micro, Single-AZ ~$15–25
Container Registry AWS ECR First 500MB free, then $0.10/GB ~$1–5
Monitoring CloudWatch Logs App Runner logs ~$2–5
BetterStack Uptime monitoring Free tier (3 monitors) $0
Total ~$43–85/month

Cost Optimization Notes:

  • App Runner scales to minimum instances in off-peak; staging (Fly.io) scales to zero.
  • db.t4g.micro is ARM-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 (App Runner) App Runner managed multi-instance Immediate (health check driven) App Runner restarts unhealthy instances automatically
Database (RDS) Single-AZ with automated backups 30 min (snapshot restore) Multi-AZ planned for v1.0
Staging (Fly.io) Single machine, scale-to-zero Auto-start on request No HA for staging
External services N/A — no Drop-managed HA Depends on provider SLA Sumsub, BankID managed externally

RTO Target: 10 minutes (App Runner restart) / 30 minutes (RDS restore) RPO Target: 5 minutes (RDS PITR) / 24 hours (daily snapshot)


9. Multi-Region Considerations

Current: Single-region (eu-west-1 Ireland) Primary Region: eu-west-1 (Ireland) Secondary Region: eu-north-1 (Stockholm) — manual failover target only

Rationale: Single-region deployment appropriate for MVP/pre-production phase. Norwegian users served well from eu-west-1. GDPR data residency satisfied within EU. Cost-benefit favours backup-based recovery over active-active replication at current scale.

Data Replication: None (manual snapshot copy to eu-north-1 on region failover) Failover Procedure: See disaster-recovery-plan.md



Approval

Role Name Date Signature
Author Platform Architect (AI) 2026-02-23
Reviewer
Approver Alem Bašić