Skip to main content
TenderCheck AI ships with a Docker Compose configuration that makes it straightforward to spin up the backend service in an isolated container — ideal for local development or self-hosted production deployments on any Linux server. The Compose file mounts the backend source directory as a volume so that code changes are picked up without rebuilding the image.

Prerequisites

Docker 24+

Install Docker Desktop (Mac/Windows) or Docker Engine (Linux). Compose v2 is bundled with Docker 24+.

Turso Credentials

A Turso database URL and auth token. See Environment Variables for details.

Google AI Studio Key

A Gemini API key from Google AI Studio for the AI analysis pipeline.

Git

The repository cloned locally so Docker can build from the source tree.

Docker Compose Configuration

The docker-compose.yml at the repository root defines the backend service for local development:
Service breakdown:
  • build.context: ./backend — Docker uses backend/ as the build context, so the backend/Dockerfile is resolved relative to that directory.
  • build.target: builder — Uses only the first (builder) stage of the multi-stage Dockerfile, which retains dev dependencies so that hot-reload tooling is available.
  • ports: "3000:3000" — Maps container port 3000 to host port 3000.
  • volumes: ./backend:/app — Bind-mounts the local backend/ directory into /app inside the container, enabling live code reloading without image rebuilds.
  • /app/node_modules — An anonymous volume shadows the bind-mounted node_modules directory so the container’s installed packages are not overwritten by the host directory.
  • command: npm run dev — Overrides the Dockerfile CMD and starts the backend in watch mode.

Running with Docker Compose

1

Clone the repository

2

Create the backend environment file

Copy the example and fill in your credentials:
At minimum, set the following variables in backend/.env:
See Environment Variables for the full variable reference.
3

Build and start the containers

Docker will build the tendercheck-backend-dev image from backend/Dockerfile (builder stage) and start the container. The backend starts in watch mode and reloads on file changes.
4

Verify the services are running

Once the containers are up, you can reach:
The Docker Compose file only defines the backend service. To run the frontend locally, start it separately with npm run dev inside the frontend/ directory. The Vite dev server is configured in frontend/vite.config.ts to run on http://localhost:3000, with API requests proxied to the backend at http://localhost:3001.
5

Stop the containers

Press Ctrl+C in the terminal where Compose is running, or from a separate terminal:

Individual Dockerfiles

Backend Dockerfile (backend/Dockerfile)

The backend uses a two-stage multi-stage build based on the official node:20-alpine image:
Key details:
  • Node.js 20 on Alpine — Produces a small, security-hardened image.
  • npm ci — Installs exact locked versions from package-lock.json for reproducible builds.
  • npm run build + npm prune --production — Compiles TypeScript to dist/ then strips dev dependencies before the final image copy, minimizing image size.
  • USER node — Runs the process as the unprivileged node user rather than root.
  • EXPOSE 3000 — Documents the port; the actual binding is controlled by the PORT environment variable at runtime.

Root Dockerfile (Dockerfile)

The repository root also contains a Dockerfile targeting GPU-accelerated deployments (e.g. Hugging Face Spaces). It uses nvidia/cuda:12.1.0-base-ubuntu22.04 as both the builder and runtime base, installs Node.js 20 from NodeSource, builds both the backend and frontend, and additionally installs and pre-pulls Ollama models (mistral and nomic-embed-text) for local inference. This Dockerfile is used by the start.sh script. It is not required for standard Vercel or Render deployments.

Production Docker Deployment

When running containers on your own server, apply the following configuration adjustments:
  • Set NODE_ENV=production in the backend container’s environment so that secure cookie flags and strict CORS enforcement are active.
  • Set TURSO_DB_URL to your production Turso database URL. Use https:// if your runtime environment does not support WebSocket connections (see the warning below).
  • Set ALLOWED_ORIGINS to your production frontend domain (e.g. https://yourdomain.com), without a trailing slash.
  • Place a reverse proxy such as Nginx or Caddy in front of the containers to handle TLS termination. Expose only the frontend port publicly and proxy /api/* requests to the backend container internally.
A minimal Caddy configuration example:

Quick Start Script

The repository root contains a start.sh script used by the GPU (Dockerfile) runtime image:
This script verifies that the frontend static assets were built, starts the Ollama inference server in the background, waits for it to initialize, then hands off to the Node.js backend process. It is only relevant when using the root Dockerfile (GPU/Ollama deployment). Standard Docker Compose and Vercel deployments do not use this script.
The backend validates the TURSO_DB_URL protocol at startup. On platforms that block WebSocket connections (including Vercel serverless functions), you must set TURSO_DB_URL to https://your-db.turso.io rather than libsql://your-db.turso.io. Using the wrong protocol will cause the database connection to fail silently or throw on the first query.
Stream the backend container logs in real time during development to watch for startup errors, CORS warnings, and AI pipeline output: