---
title: Infrastructure
tags: [architecture, infrastructure, docker, devops]
created: 2026-05-23
---

# Infrastructure

How the system is packaged, deployed and run in production. Read alongside [[Docker Setup]] (operations runbook) and [[CI-CD Pipeline]].

---

## 1. Runtime topology

```mermaid
flowchart LR
    DNS[DNS amn.gg] --> CF[CloudFlare / Edge SSL]
    CF --> Nginx
    subgraph Host[Single Docker host]
        Nginx[nginx:alpine<br/>nickapp-nginx<br/>:8083]
        FE[nickapp-frontend:latest<br/>Next.js standalone<br/>:8083]
        BE[nickapp-backend:latest<br/>Express + Socket.IO<br/>:5001]
        Mongo[(mongo:8.0<br/>mongodb_data volume)]
        Redis[(redis:8-alpine<br/>redis_data volume)]
        Up[/uploads volume/]
    end
    Nginx --> FE
    Nginx --> BE
    BE --> Mongo
    BE --> Redis
    BE --- Up
    FE --- Up
    Watchtower>Watchtower<br/>auto-update] -.-> BE
    Watchtower -.-> FE
```

> [!info]
> Single-host today. Horizontal scaling requires Redis pub/sub adapter for Socket.IO and externalizing the `uploads/` volume (S3 / R2).

---

## 2. Docker images

| Image | Source Dockerfile | Stages | Final size target | User |
|---|---|---|---|---|
| `nickapp-backend:latest` | `backend/Dockerfile.prod` | builder + runner | ~200 MB | `marketplace` (uid 1001) |
| `nickapp-backend:dev` | `backend/Dockerfile.dev` | single | ~400 MB | `marketplace` (uid 1001) |
| `nickapp-frontend:latest` | `frontend/Dockerfile` | builder + runner | ~250 MB | `nextjs` (uid 1001) |
| `nickapp-frontend:dev` | `frontend/Dockerfile.dev` | single | ~600 MB | root |

All built on `node:22-alpine`. Backend images include Python+make+g++ in the builder stage for native deps (bcrypt). Frontend runner only ships the `.next/standalone` output + `public/`.

---

## 3. Compose stacks

### 3.1 `docker-compose.dev.yml` (backend repo)

Used by developers running `npm run docker:dev`. Three services:

| Service | Image | Ports | Volumes | Depends on |
|---|---|---|---|---|
| `nickdev-backend` | built from `Dockerfile.dev` | `5001:5001` | `./src:/app/src`, `./uploads:/app/uploads` | mongodb, redis |
| `nickdev-mongodb` | `mongo:8.0` | `27017:27017` | `mongodb_data:/data/db` | — |
| `nickdev-redis` | `redis:8-alpine` | (internal) | `redis_data:/data` | — |

Network: `nickapp-network` (bridge). Env: `.env.local`.

Frontend dev runs OUTSIDE compose — developer launches `yarn dev` on host so React Fast Refresh works.

### 3.2 `docker-compose.production.yml` (backend repo)

Used in production. Five services:

| Service | Image | Ports | Healthcheck | Watchtower |
|---|---|---|---|---|
| `nickapp-nginx` | `nginx:alpine` | `8083:80` | implicit | — |
| `nickapp-backend` | `nickapp-backend:latest` (pulled) | 5001 internal | `node healthcheck.js` 30s | ✓ |
| `nickapp-frontend` | `nickapp-frontend:latest` (pulled) | 8083 internal | `curl http://localhost:8083` 30s | ✓ |
| `nickapp-mongodb` | `mongo:8.0` | internal | `mongosh ping` 30s | — |
| `nickapp-redis` | `redis:8-alpine` (with `--requirepass`) | internal | `redis-cli ping` 30s | — |

Volumes: `mongodb_data`, `redis_data`, `./uploads`, `./nginx/nginx.conf`, `./nginx/logs`. Env: single root `.env`.

> [!warning]
> `REDIS_PASSWORD` MUST be set in the production `.env` before starting — otherwise the Redis container fails its healthcheck and dependents won't start.

---

## 4. Nginx configuration

The Nginx proxy at `./nginx/nginx.conf` (mounted read-only) is responsible for:

- Terminating internal HTTP (SSL handled by an external edge — CloudFlare / nginx-proxy / Caddy)
- Routing `/api/*` and `/socket.io/*` to `nickapp-backend:5001`
- Routing everything else to `nickapp-frontend:8083`
- Serving `/uploads/*` directly from the shared volume (bypasses the Node process)
- Standard gzip / compression / client_max_body_size (≥10 MB to match backend body limit)

> [!tip]
> Put the Nginx access log path on a tmpfs or rotate it aggressively — the container exposes `./nginx/logs` so the host can manage retention.

---

## 5. Watchtower (auto-update)

Both `nickapp-backend` and `nickapp-frontend` carry the `watchtower.enable=true` label. Watchtower polls the container registry on its configured interval and re-pulls when the `latest` tag moves.

Release cycle:
1. Developer pushes commits to a feature branch → merged into the active integration branch (`integrate-main-into-development` for the current dev stack; historically `development`).
2. Manual Gitea workflow `docker-build-simple.yml` builds & pushes `nickapp-backend:latest` (and a versioned tag) to `git.manko.yoga/manawenuz/escrow-backend`.
3. Within the next poll interval (default 5 min) Watchtower restarts the affected service.

> [!warning]
> Because Watchtower restarts only on tag change, sequential pushes are safe — but a broken build pushed to `latest` will roll out automatically. Keep `dev` and `production` tags separated, or pin production to a versioned tag.

---

## 6. Persistent storage

| Volume | What it stores | Backup priority |
|---|---|---|
| `mongodb_data` | All business data (users, requests, payments, chats, disputes...) | **Critical** — daily dump |
| `postgres_data` | Postgres 18 migration/backfill store and `payment_quotes` when enabled | **Critical after cutover; medium before cutover** — dump before/after migrations |
| `redis_data` | Cache, session, rate counters | Low — losing it logs everyone out but no data loss |
| `./uploads` (host bind) | Avatars, product images, dispute evidence, documents | **High** — daily rsync |
| `./nginx/logs` | Access / error logs | Medium |

See [[Backup & Recovery]] for the runbook.

---

## 7. CI / CD

Located at `backend/.gitea/workflows/`:

| Workflow | Trigger | Output |
|---|---|---|
| `docker-build-simple.yml` | manual | Build → push backend image to registry (`latest` + version) |
| `docker-build-dev.yml` | manual | Dev image variant |
| `docker-build-no-cache.yml` | manual | Clean build (no GH-Actions cache) |

Frontend at `frontend/.gitea/workflows/`:

| Workflow | Trigger | Output |
|---|---|---|
| `deploy.yml` | push to `main`/`master`, manual | Runs `scripts/deploy.sh` (deploy via SSH) |
| `devDeploy.yml` | manual | Deploy to dev env |

Single secret required: `GITEATOKEN` (Gitea PAT with `write:package`).

Full breakdown → [[CI-CD Pipeline]].

---

## 8. Secrets

Never committed. Required in production `.env`:

- `JWT_SECRET`, `REFRESH_TOKEN_SECRET`
- `MONGODB_URI`, `REDIS_PASSWORD`
- `SHKEEPER_API_KEY`, `SHKEEPER_WEBHOOK_SECRET`
- `SMTP_USER`, `SMTP_PASS`
- `OPENAI_API_KEY`
- `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`
- `NEXT_PUBLIC_ALCHEMY_API_KEY_*` (frontend public envs — embedded at build)

Recommend storing host-side in an `.env` outside the repo, mounted via Compose. For multi-host: Vault / AWS SSM / GCP Secret Manager.

---

## 9. Observability

| Signal | Where |
|---|---|
| App logs | container `stdout` → `docker logs nickapp-backend` |
| Access logs | `./nginx/logs` |
| Frontend errors | Sentry (`@sentry/nextjs`) |
| Backend errors | Sentry (optional — add `@sentry/node`) |
| Healthchecks | `GET /health` (backend) · `GET /` (frontend) · `mongosh ping` · `redis-cli ping` |

See [[Monitoring]] for the full table of metrics & recommended alerts.

---

## 10. Networking

| Direction | Port | Protocol | Notes |
|---|---|---|---|
| Internet → Nginx | 8083 | HTTP | SSL terminated upstream |
| Browser → Backend | 5001 | HTTP + WS | via Nginx `/api`, `/socket.io` |
| Backend → MongoDB | 27017 | TCP | Docker network |
| Backend → Redis | 6379 | TCP | Docker network |
| Backend → Request Network API | 443 | HTTPS | External payment provider |
| Backend → SMTP | 587 | TLS | External |
| Backend → OpenAI | 443 | HTTPS | External |
| Browser → Blockchain RPC | 443 | HTTPS | Alchemy URLs |
| Browser → WalletConnect | 443 | HTTPS | Relay server |

---

## 11. Hardening checklist

- [ ] Non-root user inside every container (`marketplace` / `nextjs`) ✓ in Dockerfiles
- [ ] Read-only Nginx config mount ✓
- [ ] Redis requires password ✓
- [ ] MongoDB has root credentials + bind to internal network only ✓
- [ ] Rate limit enabled before public traffic ⚠ currently disabled
- [ ] Refresh tokens rotated on use ⚠ partial
- [ ] All public env values reviewed (no `IS_DEVELOPMENT=true` in prod build) ⚠
- [ ] Watchtower scoped to specific repos
- [ ] Sentry source-map upload at build time ✓ (frontend)

See [[Security Architecture]] for the deeper review.

---

## Related

- [[System Architecture]] · [[Backend Architecture]] · [[Frontend Architecture]]
- [[Docker Setup]] — operational walk-through with commands
- [[CI-CD Pipeline]] — workflow breakdown
- [[Deployment]] — first-deploy runbook
- [[Backup & Recovery]] · [[Monitoring]] · [[Incident Response]]
- [[Environment Variables]] — full env-var catalog
