Document Version: 1.0
Date: April 30, 2026
Owner: Amaturalist Development Team
Classification: Internal Use
This document provides the architecture diagram and description of Amaturalist system, focusing on security features, high availability components, and data flows.
graph TB
subgraph USER_LAYER["USER LAYER"]
WEB[Web Browser
React Frontend
JWT Authentication]
MOBILE[Mobile App
React Native
JWT Authentication]
end
subgraph CLOUDFLARE["CLOUDFLARE CDN"]
CF[Security Features:
- DDoS Protection Layer 3/4/7
- Web Application Firewall WAF
- SSL/TLS Termination Let's Encrypt
- Rate Limiting
- Bot Protection
- 200+ Edge Locations Worldwide]
end
subgraph EXABYTES["EXABYTES VPS INDONESIA"]
subgraph NGINX["NGINX WEB SERVER"]
NGINX_SEC[Security Features:
- Security Headers X-Frame-Options CSP HSTS
- SSL Configuration TLS 1.3
- Reverse Proxy
- Static File Serving]
end
subgraph LARAVEL["LARAVEL APPLICATION"]
LARAVEL_SEC[Security Features:
- JWT Authentication 7-day TTL
- Rate Limiting 5 attempts/15min
- Input Validation
- Output Encoding XSS Prevention
- CSRF Protection
- Security Logging SecurityLogger
- Password Hashing bcrypt cost 12
- RBAC Authorization]
end
subgraph MYSQL["MYSQL DATABASE"]
MYSQL_SEC[Security Features:
- Bound to localhost only
- Separate database user with limited privileges
- Encrypted sensitive fields AES-256-CBC
- Regular backups]
end
end
subgraph AWS_S3["AWS S3 SINGAPORE"]
S3_SEC[Security Features:
- Server-side Encryption SSE-S3 AES-256
- IAM Roles for Access Control
- Bucket Policies Least Privilege
- Versioning Enabled
- Access Logging
- ISO 27001 SOC 1/2/3 Certified]
end
WEB -->|HTTPS TLS 1.3| CF
MOBILE -->|HTTPS TLS 1.3| CF
CF -->|HTTPS| NGINX_SEC
NGINX_SEC -->|Reverse Proxy| LARAVEL_SEC
LARAVEL_SEC -->|Query| MYSQL_SEC
MYSQL_SEC -->|Backup Encrypted| S3_SEC
style USER_LAYER fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style CLOUDFLARE fill:#0a0a0a,stroke:#0066cc,stroke-width:2px,color:#ffffff
style EXABYTES fill:#0a0a0a,stroke:#0066cc,stroke-width:2px,color:#ffffff
style AWS_S3 fill:#0a0a0a,stroke:#0066cc,stroke-width:2px,color:#ffffff
style WEB fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style MOBILE fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style CF fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style NGINX_SEC fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style LARAVEL_SEC fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style MYSQL_SEC fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style S3_SEC fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph LR
subgraph FIREWALL["FIREWALL UFW"]
INBOUND["INBOUND:
- DENY ALL Default
- ALLOW SSH 22/tcp From specific IPs only
- ALLOW HTTP 80/tcp
- ALLOW HTTPS 443/tcp
- DENY DATABASE 3306/tcp From public"]
OUTBOUND["OUTBOUND:
- ALLOW ALL Default"]
end
style FIREWALL fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style INBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style OUTBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph TB
LAYER1["Layer 1: Cloudflare Network Security
- DDoS Protection
- WAF Web Application Firewall
- Rate Limiting
- SSL/TLS Termination"]
LAYER2["Layer 2: Nginx Web Server Security
- Security Headers
- SSL Configuration
- Reverse Proxy
- Static File Security"]
LAYER3["Layer 3: Laravel Application Security
- JWT Authentication
- Rate Limiting
- Input Validation
- Output Encoding
- CSRF Protection
- Security Logging"]
LAYER4["Layer 4: MySQL Database Security
- Localhost Only Binding
- Limited Privileges
- Encrypted Fields"]
LAYER1 --> LAYER2
LAYER2 --> LAYER3
LAYER3 --> LAYER4
style LAYER1 fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style LAYER2 fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style LAYER3 fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style LAYER4 fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph TB
subgraph HA["HIGH AVAILABILITY COMPONENTS"]
CDN["CDN Cloudflare:
- 200+ Edge Locations Worldwide
- Automatic Failover
- Load Balancing"]
BACKUP["Backup Strategy:
- Daily Off-site Backup AWS S3 Singapore
- 90-day Retention for Critical Data
- RTO: 4 hours
- RPO: 6 hours"]
MONITOR["Monitoring:
- Uptime Monitoring UptimeRobot Planned
- Security Event Logging
- Automated Alerts"]
end
style HA fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style CDN fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style BACKUP fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style MONITOR fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph TB
subgraph PLANNED["PLANNED HIGH AVAILABILITY ENHANCEMENTS"]
MULTI["Multi-Region Deployment:
- Primary: Indonesia Exabytes
- Secondary: Singapore AWS
- Automatic Failover"]
REPLICATION["Database Replication:
- Master-Slave Replication
- Read Replicas
- Automatic Failover"]
LOAD_BAL["Load Balancing:
- Application Load Balancer
- Database Load Balancer
- Session Management Redis Cluster"]
end
style PLANNED fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style MULTI fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style REPLICATION fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style LOAD_BAL fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph TD
USER["User Request Login"]
CF["Cloudflare
DDoS Protection WAF"]
NGINX["Nginx
HTTPS Termination
Security Headers"]
RATE["Laravel
Rate Limiting Check"]
AUTH["Laravel
JWT Authentication"]
DB["MySQL
User Verification"]
TOKEN["JWT Token Generation"]
RESPONSE["Response to User
JWT Token"]
USER --> CF
CF --> NGINX
NGINX --> RATE
RATE --> AUTH
AUTH --> DB
DB --> TOKEN
TOKEN --> RESPONSE
style USER fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style CF fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style NGINX fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style RATE fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style AUTH fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style DB fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style TOKEN fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style RESPONSE fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph TD
UPLOAD["User Upload Image"]
CF["Cloudflare
DDoS Protection WAF"]
NGINX["Nginx
File Upload Handling"]
AUTH_CHECK["Laravel
Authentication Check"]
VALIDATION["Laravel
Input Validation"]
PROCESSING["Laravel
Image Processing"]
S3["S3 Upload
Encrypted"]
MYSQL["MySQL
Metadata Storage"]
SUCCESS["Response to User
Success"]
UPLOAD --> CF
CF --> NGINX
NGINX --> AUTH_CHECK
AUTH_CHECK --> VALIDATION
VALIDATION --> PROCESSING
PROCESSING --> S3
S3 --> MYSQL
MYSQL --> SUCCESS
style UPLOAD fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style CF fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style NGINX fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style AUTH_CHECK fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style VALIDATION fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style PROCESSING fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style S3 fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style MYSQL fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style SUCCESS fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph TD
SCHEDULED["Scheduled Backup
02:00 WIB"]
DUMP["MySQL Dump
Encrypted"]
COMPRESS["Compress
Gzip"]
UPLOAD_S3["Upload to AWS S3 Singapore"]
VERIFY["Verify Integrity
Hash Check"]
RETENTION["Retention Policy
30/90/365 days"]
LOG["Log Backup Event"]
SCHEDULED --> DUMP
DUMP --> COMPRESS
COMPRESS --> UPLOAD_S3
UPLOAD_S3 --> VERIFY
VERIFY --> RETENTION
RETENTION --> LOG
style SCHEDULED fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style DUMP fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style COMPRESS fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style UPLOAD_S3 fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style VERIFY fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style RETENTION fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style LOG fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph TD
EVENT["Security Event
e.g. Failed Login"]
LOGGER["Laravel
SecurityLogger Service"]
LOG_FILE["Log to security.log
JSON Format"]
EMAIL["Send Email Notification
Critical Events"]
ROTATE["Rotate Log
Daily"]
UPLOAD_S3["Upload to S3
Optional - 90 days retention"]
EVENT --> LOGGER
LOGGER --> LOG_FILE
LOG_FILE --> EMAIL
EMAIL --> ROTATE
ROTATE --> UPLOAD_S3
style EVENT fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style LOGGER fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style LOG_FILE fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style EMAIL fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style ROTATE fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style UPLOAD_S3 fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph TB
subgraph EXABATES["EXABATES VPS INDONESIA"]
APP["Application Storage:
- /var/www/html Application Code
- /var/www/storage Local Storage
- /var/log Application Logs"]
DB["Database Storage:
- MySQL Database Local Disk
- Encrypted Sensitive Fields
- Regular Backups to S3"]
end
style EXABATES fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style APP fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style DB fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
graph LR
subgraph FIREWALL["FIREWALL UFW"]
INBOUND["INBOUND:
- DENY ALL Default
- ALLOW SSH 22/tcp From specific IPs only
- ALLOW HTTP 80/tcp
- ALLOW HTTPS 443/tcp
- DENY DATABASE 3306/tcp From public"]
OUTBOUND["OUTBOUND:
- ALLOW ALL Default"]
end
style FIREWALL fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style INBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style OUTBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff0
graph LR
subgraph FIREWALL["FIREWALL UFW"]
INBOUND["INBOUND:
- DENY ALL Default
- ALLOW SSH 22/tcp From specific IPs only
- ALLOW HTTP 80/tcp
- ALLOW HTTPS 443/tcp
- DENY DATABASE 3306/tcp From public"]
OUTBOUND["OUTBOUND:
- ALLOW ALL Default"]
end
style FIREWALL fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style INBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style OUTBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff1
graph LR
subgraph FIREWALL["FIREWALL UFW"]
INBOUND["INBOUND:
- DENY ALL Default
- ALLOW SSH 22/tcp From specific IPs only
- ALLOW HTTP 80/tcp
- ALLOW HTTPS 443/tcp
- DENY DATABASE 3306/tcp From public"]
OUTBOUND["OUTBOUND:
- ALLOW ALL Default"]
end
style FIREWALL fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style INBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style OUTBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff2
graph LR
subgraph FIREWALL["FIREWALL UFW"]
INBOUND["INBOUND:
- DENY ALL Default
- ALLOW SSH 22/tcp From specific IPs only
- ALLOW HTTP 80/tcp
- ALLOW HTTPS 443/tcp
- DENY DATABASE 3306/tcp From public"]
OUTBOUND["OUTBOUND:
- ALLOW ALL Default"]
end
style FIREWALL fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style INBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style OUTBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff3
graph LR
subgraph FIREWALL["FIREWALL UFW"]
INBOUND["INBOUND:
- DENY ALL Default
- ALLOW SSH 22/tcp From specific IPs only
- ALLOW HTTP 80/tcp
- ALLOW HTTPS 443/tcp
- DENY DATABASE 3306/tcp From public"]
OUTBOUND["OUTBOUND:
- ALLOW ALL Default"]
end
style FIREWALL fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style INBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style OUTBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff4
graph LR
subgraph FIREWALL["FIREWALL UFW"]
INBOUND["INBOUND:
- DENY ALL Default
- ALLOW SSH 22/tcp From specific IPs only
- ALLOW HTTP 80/tcp
- ALLOW HTTPS 443/tcp
- DENY DATABASE 3306/tcp From public"]
OUTBOUND["OUTBOUND:
- ALLOW ALL Default"]
end
style FIREWALL fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style INBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style OUTBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff5
graph LR
subgraph FIREWALL["FIREWALL UFW"]
INBOUND["INBOUND:
- DENY ALL Default
- ALLOW SSH 22/tcp From specific IPs only
- ALLOW HTTP 80/tcp
- ALLOW HTTPS 443/tcp
- DENY DATABASE 3306/tcp From public"]
OUTBOUND["OUTBOUND:
- ALLOW ALL Default"]
end
style FIREWALL fill:#000000,stroke:#0066cc,stroke-width:2px,color:#ffffff
style INBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff
style OUTBOUND fill:#0066cc,stroke:#0088ff,stroke-width:1px,color:#ffffff6
This architecture diagram represents the current implementation as of April 30, 2026, with planned enhancements for high availability and disaster recovery.