┌─────────────────────────┐
│ INTERNET │
│ app.discoverant.com │
└────────────┬────────────┘
│ :443 TLS
┌────────────▼────────────┐
│ Nginx (Gateway) │
│ adroit-nginx :80 │
└──┬─────────────────┬────┘
│ │
/app/* │ │ /api/*
│ │
┌────────────▼──┐ ┌────────▼──────────┐
│ Frontend │ │ Backend │
│ React/TS │ │ FastAPI/Python │
│ :3100 │ │ :8000 │
└───────────────┘ └──┬──────────┬─────┘
│ │
┌──────────▼──┐ ┌───▼───────┐
│ PgBouncer │ │ Redis │
│ :6432 │ │ :6379 │
└──────┬──────┘ └───────────┘
│
┌─────────▼──────────┐
│ PostgreSQL 16 │
│ + Bingo Cart. │
│ :5432 │
│ │
│ 88 GB / 174M rows │
└────────────────────┘
| Container | Image | Port | Role |
|---|---|---|---|
adroit-nginx |
nginx:alpine | :80 / :443 | Reverse proxy, TLS termination, static assets, routing |
adroit-frontend |
node:18 + nginx | :3100 | React SPA — chemistry UI, importers, dashboards |
adroit-backend |
python:3.11 | :8000 | FastAPI application server — REST API, Indigo, RDKit |
adroit-postgres |
postgres:16 + bingo | :5432 | Primary datastore — chemistry databases, Bingo cartridge |
adroit-redis |
redis:alpine | :6379 | Session cache, task queue, temporary result storage |
pgbouncer |
pgbouncer | :6432 | Connection pooling for PostgreSQL |
The gateway nginx instance handles all inbound traffic for app.discoverant.com:
| Path Pattern | Upstream | Notes |
|---|---|---|
/, /app/* |
frontend :3100 | React SPA, client-side routing |
/api/* |
backend :8000 | All REST API endpoints |
/api/docs |
backend :8000 | Swagger/OpenAPI interactive docs |
/ws/* |
backend :8000 | WebSocket upgrade for live tasks |
resolver 127.0.0.11; # Docker embedded DNS
set $backend http://backend:8000; # Variable to avoid stale DNS caching
set $frontend http://frontend:3100;
location /api/ {
proxy_pass $backend; # No trailing URI — preserves original path
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
Important: The $backend variable approach with resolver directive prevents nginx from caching DNS at startup. Do NOT use literal hostnames or 172.17.0.1 (wrong Docker network).
| Port | Service | Exposure | Description |
|---|---|---|---|
:80 |
Nginx | Public | HTTP (redirects to :443) |
:443 |
Nginx | Public | HTTPS — TLS termination |
:3100 |
Frontend | Internal | React dev / nginx serving built assets |
:8000 |
Backend | Internal | FastAPI (Uvicorn, WatchFiles reload) |
:5432 |
PostgreSQL | Internal | Database (with Bingo cartridge) |
:6432 |
PgBouncer | Internal | Connection pooler for PostgreSQL |
:6379 |
Redis | Internal | Cache and task queue |
Primary datastore hosting 88 GB across 174M+ rows. The EPAM Bingo cartridge provides chemical-aware indexing for substructure and similarity search directly in SQL.
adroit_chemistrybingo.searchSub(), bingo.searchSim(), bingo.checkMolecule()patent_chem.surechembl_compounds, compounds.pubchem, compounds.chembl/api/v1/auth/loginlocalStorage, sends as Authorization: Bearerget_current_user dependencytenant_id# Build and deploy (requires rebuild for changes) docker compose build frontend docker compose up -d frontend
The backend uses Uvicorn with WatchFiles — code changes are automatically detected and reloaded. No rebuild required for Python changes.
# Only needed for dependency changes docker compose build backend docker compose up -d backend
# Copy SQL into container, then execute docker cp migration.sql adroit-postgres:/tmp/ docker exec -i adroit-postgres psql -U adroit_user -d adroit_chemistry -f /tmp/migration.sql
| Component | Specification |
|---|---|
| Model | Dell OptiPlex 7060 |
| CPU | Intel Core i7-8700 (6C/12T, 3.2 GHz base / 4.6 GHz turbo) |
| RAM | 32 GB DDR4 |
| Storage | 2 TB SSD |
| OS | Ubuntu Linux |
| Docker | Docker Compose (6 containers) |