Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/No-Country-simulation/G9-LATAM-Team-58/llms.txt

Use this file to discover all available pages before exploring further.

Mindloom’s production stack runs entirely on a single OCI Ampere A1 virtual machine (linux/arm64) orchestrated by Docker Compose. Three services — inference, api, and web — form a dependency chain: the Python inference service must reach a healthy state before the Spring Boot API starts, and the React frontend served by nginx depends on the API. Because OCI Object Storage cannot host a single-page application (a browser refresh on any deep route returns a 404 with no index.html fallback), the nginx container serves the built React bundle directly from the VM rather than from a bucket.

Services and Ports

The compose file defines three services on a shared bridge network named techmind. The table below shows how each service is exposed:
ServicePort mappingNotes
inferenceexpose: 8000Internal network only — port 8000 is not published to the host
api8080:8080Published to the host for direct API access
web80:80Published to the host; requires --profile web
The inference service uses expose rather than ports, meaning port 8000 is reachable only by other containers on the techmind network. Port 8000 remains closed in the OCI Security List. Port 8080 is published while the frontend is being built so teammates can call the API directly; once all traffic routes through nginx’s /api proxy, it can be changed to expose and closed.

Startup Order and Healthcheck

The api service declares a hard dependency on inference reaching a healthy state:
depends_on:
  inference:
    condition: service_healthy
The inference healthcheck is defined in its Dockerfile:
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
  CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8000/health').status==200 else 1)"
The start-period of 60 seconds gives the load() function time to authenticate with OCI Object Storage via Instance Principal, fetch models/latest.txt, download the joblib artifact it points to, and deserialize the model into memory. The API container will not start until that window completes successfully.
The inference healthcheck uses Python’s built-in urllib rather than curl because the python:3.12-slim base image does not include curl. This keeps the image layer small.

Model Loading at Startup

When the inference container starts, its load() function executes two sequential reads from OCI Object Storage:
  1. GET models/latest.txt — a small pointer file that contains the path prefix of the current model version (e.g. models/v1/).
  2. GET models/v1/model.joblib — the ~0.24 MB serialized scikit-learn pipeline downloaded into memory via joblib.load().
Authentication on the OCI VM uses Instance Principal — no API key files or OCI CLI secrets are required on the VM. Locally, the same code falls back to ~/.oci/config. The SentenceTransformer weights (~470 MB for intfloat/multilingual-e5-small) are baked into the image at build time and loaded from the local HF_HOME=/app/.cache/huggingface cache at startup — no network call to Hugging Face occurs at runtime.

The web Profile

The web service is declared behind profiles: [web] in docker-compose.yml. A plain docker compose build or docker compose up does not include it. The deploy workflow always passes --profile web explicitly:
docker compose --profile web build
docker compose --profile web up -d --remove-orphans
This means a developer running docker compose up locally for API and inference development is unaffected by any frontend changes.

Oracle Wallet Mount

The API container requires the Oracle Autonomous Database wallet to be available at runtime. The wallet is never stored in the repository — it must be unzipped into ./wallet/ on the VM (relative to docker-compose.yml) before the first deploy. Docker Compose mounts it read-only:
volumes:
  - ./wallet:/app/wallet:ro
The TNS_ADMIN environment variable in the container is set to /app/wallet, matching the mount point. The SPRING_DATASOURCE_URL uses the TNS alias techmind_tp from the wallet’s tnsnames.ora:
jdbc:oracle:thin:@techmind_tp?TNS_ADMIN=/app/wallet

The db Spring Profile

The api service sets SPRING_PROFILES_ACTIVE=db in docker-compose.yml. This activates application-db.properties, which sets app.database.enabled=true and removes the scaffold-mode spring.autoconfigure.exclude entries that disable the DataSource and JPA autoconfiguration. Without the db profile, the API starts in scaffold mode and every DB-backed endpoint returns 503 Service Unavailable.

First-Time VM Setup

1

Clone the repository

SSH into the OCI Ampere A1 VM and clone the repository to ~/techmind:
git clone https://github.com/No-Country-simulation/G9-LATAM-Team-58.git ~/techmind
cd ~/techmind
2

Create and fill the environment file

Copy .env.example to .env and fill in the credentials. The .env file lives at ~/techmind/.env and is never committed to the repository:
cp .env.example .env
# Edit .env and set SPRING_DATASOURCE_PASSWORD, OCI_NAMESPACE, and the other variables
3

Install the Oracle wallet

Download the Oracle Autonomous Database Instance Wallet from the OCI Console and unzip it into ~/techmind/wallet/:
mkdir -p ~/techmind/wallet
unzip Wallet_techmind.zip -d ~/techmind/wallet/
The wallet directory must exist at ./wallet/ relative to docker-compose.yml before the API container starts.
4

Build the Docker images

Build all images natively on the ARM64 VM. Pass --profile web to include the nginx frontend:
docker compose --profile web build
This step downloads the intfloat/multilingual-e5-small transformer weights (~470 MB) into the inference image layer on first build.
5

Start the stack

Bring up all three containers in detached mode:
docker compose --profile web up -d
The inference container starts first. After load() succeeds and the healthcheck passes (up to 60 seconds), Docker Compose automatically starts the API. The web container starts once the API is up.
6

Verify startup

Check the status of all running containers:
docker compose ps
All three services should show Up or Up (healthy) status. If inference shows starting for more than 90 seconds, check its logs with docker compose logs inference.
The OCI Ampere A1 VM runs linux/arm64. Docker images built on x86 machines — including GitHub Actions runners — will fail immediately with exec format error when the container tries to start. All builds must run natively on the ARM64 VM itself. See the CI/CD guide for the full rationale.
The deploy workflow runs git reset --hard origin/main on the VM during every deployment. Any files you modify manually inside the ~/techmind git tree will be overwritten and lost on the next deploy. Files that live outside the git tree — .env, wallet/ — survive because git reset does not touch untracked files.

Build docs developers (and LLMs) love