BOL System Architecture Document
Deployment topology, security architecture, data flow, technology stack, and operational procedures.
Download PDF1. System Overview
1.1 Purpose
This document describes the system architecture of BOL (Beginning of Life), a full-stack Python application that simulates prebiotic chemistry and the emergence of the first protocells. It covers the deployment topology, component interactions, security architecture, data flow, technology stack, and operational procedures.
1.2 System Context
BOL operates as a single-server web application serving a browser-based dashboard. The system has no external database dependencies — all persistent data is stored as JSON files on the local filesystem. The simulation engine runs in-process alongside the web server.
1.3 Key Characteristics
- Self-contained — No external databases, message queues, or microservices.
- Single-process — Flask app + simulation thread in one Python process (Gunicorn multi-worker in production).
- File-based persistence — JSON files for users, projects, scenarios, training, and bugs.
- Real-time — Polling-based live updates from running simulation to browser.
2. Deployment Topology
2.1 Production Architecture
┌───────────────────────────────────────────────────────┐
│ Client (Browser / PWA) │
│ • Dashboard, Microscope, AI Lab, Projects, etc. │
│ • Chart.js, Three.js, vanilla JS │
└──────────────────────┬────────────────────────────────┘
│ HTTPS (443)
┌──────────────────────▼────────────────────────────────┐
│ Nginx Reverse Proxy │
│ • SSL termination (Let's Encrypt) │
│ • bol.drel.us → 127.0.0.1:5000 │
│ • drel.us → static HTML landing page │
│ • Security headers (CSP, HSTS, X-Frame-Options) │
│ • Static file serving (/static/ → /opt/bol/...) │
│ • 10 MB upload limit │
└──────────────────────┬────────────────────────────────┘
│ HTTP (5000, localhost only)
┌──────────────────────▼────────────────────────────────┐
│ Gunicorn WSGI Server │
│ • 3 worker processes │
│ • 120-second request timeout │
│ • Managed by systemd (bol.service) │
│ • Auto-restart on failure (RestartSec=5) │
└──────────────────────┬────────────────────────────────┘
│
┌──────────────────────▼────────────────────────────────┐
│ Flask Application (bol.web.server) │
│ • Page routes (30+ HTML templates) │
│ • REST API endpoints (40+ routes) │
│ • Authentication & session management │
│ • Security middleware (headers, rate limiting) │
│ • PDF document generation │
├───────────────────────────────────────────────────────┤
│ Simulation Engine (background thread) │
│ • Stochastic chemistry (27 reactions) │
│ • Self-assembly (micelles → vesicles) │
│ • RNA replication with mutations │
│ • Metrics collection & export │
├───────────────────────────────────────────────────────┤
│ File System Storage │
│ • profiles/*.json (user accounts) │
│ • projects/*.json (experiment projects) │
│ • scenarios/*.json (4 preset scenarios) │
│ • training/modules.json (curriculum) │
│ • bugs/bugs.json (bug tracker) │
│ • .secret_key (session signing key) │
│ • output/ (CSV/JSON exports) │
└───────────────────────────────────────────────────────┘
Target: GCP Compute Engine (e2-small, Ubuntu 24.04 LTS)
Domains: drel.us (landing), bol.drel.us (app)
2.2 Local Development
Browser ──► http://127.0.0.1:5000 ──► Flask dev server (single thread)
│
├── Simulation (background thread)
└── File system (profiles/, projects/, etc.)
Local mode differences: no Nginx, no SSL, no Gunicorn, SESSION_COOKIE_SECURE=False.
2.3 Network Configuration
| Port | Protocol | Service | Access |
|---|---|---|---|
| 22 | TCP | SSH | Admin only (key-based auth) |
| 80 | TCP | HTTP | Public (redirects to 443) |
| 443 | TCP | HTTPS | Public (Nginx → Gunicorn) |
| 5000 | TCP | Gunicorn | Localhost only (127.0.0.1) |
3. Security Architecture
3.1 NIST SP 800-53 Control Mapping
| Control | Title | Implementation |
|---|---|---|
| AC-7 | Unsuccessful Login Attempts | IP-based rate limiting: 10 attempts per 5-minute window; returns 429 on excess |
| IA-5 | Authenticator Management | PBKDF2-HMAC-SHA256, 260K iterations, 32-byte salt; min 8 chars + upper/lower/digit |
| SC-8 | Transmission Confidentiality | TLS 1.2+ via Let’s Encrypt; HSTS with 1-year max-age |
| SC-13 | Cryptographic Protection | PBKDF2 for passwords; secrets.token_hex for session keys; timing-safe comparison |
| SI-10 | Information Input Validation | Allowlist validation on all user-supplied identifiers (usernames, IDs, filenames) |
| SI-11 | Error Handling | Generic error messages to users; detailed errors logged server-side only |
| AC-3 | Access Enforcement | Resource ownership enforcement; admin-only endpoints; session-based auth |
| AU-2 | Audit Events | Gunicorn access/error logs; simulation event logging |
3.2 CISA Compliance
| Directive | Requirement | Implementation |
|---|---|---|
| BOD 18-01 | HTTPS enforcement | Nginx redirects HTTP→HTTPS; HSTS header; Secure cookie flag in production |
| BOD 22-01 | Known exploited vulnerabilities | Dependencies pinned to recent versions; regular updates via pip |
3.3 Security Headers
Applied by both Flask middleware (@app.after_request) and Nginx:
| Header | Value | Purpose |
|---|---|---|
| Content-Security-Policy | default-src 'self'; script-src 'self' 'unsafe-inline' cdn...; ... | Prevent XSS, data exfiltration |
| Strict-Transport-Security | max-age=31536000; includeSubDomains | Force HTTPS for 1 year |
| X-Content-Type-Options | nosniff | Prevent MIME sniffing |
| X-Frame-Options | SAMEORIGIN | Prevent clickjacking |
| Referrer-Policy | strict-origin-when-cross-origin | Limit referrer leakage |
| Permissions-Policy | camera=(), microphone=(), geolocation=(), payment=() | Disable unnecessary browser APIs |
| X-XSS-Protection | 1; mode=block | Legacy XSS filter activation |
3.4 Authentication & Session Security
- Password storage — PBKDF2-HMAC-SHA256, 260,000 iterations, 32-byte random salt per user.
- Password policy — Minimum 8 characters; must contain uppercase letter, lowercase letter, and digit.
- Session cookies — HttpOnly (no JS access), SameSite=Lax (CSRF mitigation), Secure (production only).
- Session lifetime — 8-hour expiry with
PERMANENT_SESSION_LIFETIME. - Secret key persistence — Session signing key stored in
.secret_keyfile (gitignored); sessions survive server restarts. - Timing-safe comparison —
secrets.compare_digest()for password verification prevents timing attacks.
3.5 Input Validation & Output Encoding
- Server-side — Usernames validated against
[a-zA-Z0-9_-]allowlist. Project IDs, lesson IDs, and filenames sanitised before filesystem access. JSON request bodies parsed with schema validation. - Template engine — Jinja2 auto-escaping enabled globally. No
|safefilter usage in templates. - Client-side —
escHtml()/_esc()helper functions andtextContentused for safe DOM updates. All user-supplied strings escaped before insertion. - Command injection prevention —
shlex.split()withshell=Falsefor subprocess execution. URL scheme validation (HTTP/HTTPS only) prevents SSRF.
4. Technology Stack
4.1 Backend
| Layer | Technology | Version | Role |
|---|---|---|---|
| Language | Python | 3.12+ | All server-side code |
| Web Framework | Flask | ≥3.0 | HTTP routing, templating, sessions |
| WSGI Server | Gunicorn | Latest | Production multi-worker serving |
| Reverse Proxy | Nginx | Latest | SSL termination, static files, headers |
| Numerical | NumPy | ≥1.24 | Vectorised simulation computations |
| Statistical | SciPy | ≥1.10 | Metrics computation |
| Plotting | Matplotlib | ≥3.7 | CLI chart generation |
| 3D Desktop | Vispy | ≥0.14 | GPU-accelerated particle rendering |
4.2 Frontend
| Technology | Role |
|---|---|
| Jinja2 | Server-side HTML templating with auto-escaping |
| Vanilla JavaScript | Dashboard polling, DOM manipulation, event handling |
| Chart.js (CDN) | Line, bar, and pie charts for real-time metrics |
| Three.js (CDN) | WebGL 3D particle viewer with vesicle shells |
| Font Awesome 6 (CDN) | Icon library |
| CSS3 Custom Properties | Splunk-themed dark UI with responsive breakpoints |
| Canvas 2D API | Procedural microscope renderer (9 magnification levels) |
| Web Speech API | Text-to-speech for training lesson reader |
| Service Worker | PWA offline caching and install-to-home-screen |
4.3 Infrastructure
| Component | Technology | Details |
|---|---|---|
| Cloud | GCP Compute Engine | e2-small (2 vCPU, 2 GB RAM) |
| OS | Ubuntu 24.04 LTS | Long-term support until 2034 |
| Process Manager | systemd | Auto-restart, env vars, logging |
| SSL | Let’s Encrypt + certbot | Auto-renewal via cron |
| Firewall | ufw | Allow SSH (22), HTTP (80), HTTPS (443) |
| Data Storage | Local filesystem | JSON files, no external database |
5. Data Flow Architecture
5.1 Request/Response Flow
Browser ──HTTPS──► Nginx ──HTTP──► Gunicorn ──► Flask Route
│
┌───────────┴───────────┐
▼ ▼
Page Route API Route
(Jinja2 → HTML) (→ JSON)
│
┌─────────┴────────┐
▼ ▼
Read/Write Simulation
JSON files state query
5.2 Simulation Data Flow
Config ──► Simulation.init()
│
┌───────┴──────────────────────────────────────┐
│ Step Loop (background thread) │
│ ┌─────────────────────────────────────────┐ │
│ │ 1. world.diffuse(molecules) │ │
│ │ 2. energy.update(world) │ │
│ │ 3. chemistry.react(molecules, world) │ │
│ │ 4. assembly.step(molecules, world) │ │
│ │ 5. replication.step(molecules, world) │ │
│ │ 6. metrics.compute(molecules, ...) │ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ metrics_history[] │
└───────────────────┬──────────────────────────┘
│
┌───────┴──────────┐
▼ ▼
GET /api/state GET /api/history
(latest record) (time series)
5.3 Authentication Flow
POST /api/profile/loginwith{"username": "...", "password": "..."}- Server checks rate limit (IP-based, 10/5min window)
- Server loads profile JSON, computes PBKDF2 hash with stored salt
- Timing-safe comparison with stored hash (
secrets.compare_digest) - On success: set
session["username"],session.permanent = True, return 200 - On failure: return 401 with generic error message, record attempt
6. Operational Procedures
6.1 Service Management
# Check service status sudo systemctl status bol # Restart the application sudo systemctl restart bol # View application logs sudo journalctl -u bol -f tail -f /var/log/bol-access.log tail -f /var/log/bol-error.log # Check Nginx sudo nginx -t sudo systemctl reload nginx
6.2 Deployment Update Procedure
- Run tests locally:
python -m pytest tests/ -v - Deploy to server:
.\deploy\deploy_to_server.ps1 - SSH to server and restart service:
sudo systemctl restart bol - Verify HTTPS endpoint is responding
- Check logs for errors:
sudo journalctl -u bol --since "5 minutes ago"
6.3 SSL Certificate Renewal
Certbot is configured for automatic renewal via cron/systemd timer. Manual renewal:
sudo certbot renew --dry-run # Test renewal sudo certbot renew # Actual renewal
6.4 Backup Strategy
- Code — Git repository; deploy from local machine via rsync.
- User data —
profiles/,projects/,bugs/,training/directories. Should be backed up periodically. - Secret key —
.secret_keyfile. Loss invalidates all active sessions (users must re-login).
6.5 Monitoring
- Uptime — systemd auto-restart with
RestartSec=5recovers from crashes within seconds. - Access logging — Gunicorn access log at
/var/log/bol-access.log. - Error logging — Gunicorn error log at
/var/log/bol-error.log. - Firewall — ufw allows only ports 22, 80, 443; all others denied by default.
7. Scalability Considerations
7.1 Current Capacity
- Concurrent users — Gunicorn’s 3 workers can serve ~50 concurrent browser sessions.
- Simulation size — Up to ~10,000 molecules per simulation with acceptable step latency.
- Storage — JSON files are lightweight; thousands of projects and profiles feasible on SSD.
7.2 Scaling Options
- Vertical — Upgrade to larger GCP instance (e2-medium or e2-standard) for more CPU/RAM.
- Worker processes — Increase Gunicorn workers (currently 3) to match available CPU cores.
- Database migration — If file-based storage becomes a bottleneck, migrate to SQLite or PostgreSQL.
- CDN — Serve static assets via CloudFlare or GCP Cloud CDN for global performance.