Mindloom is organized into four discrete layers that each own a single concern: the Web layer handles user interaction, the API layer validates and orchestrates, the Inference Service handles all machine learning, and Oracle Autonomous Database handles persistence and vector similarity search. No layer reaches past its immediate neighbor — the web never calls inference, and inference never touches the database.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.
The Four Layers
Web — React + Vite
Serves the user-facing interface for ingesting content, browsing the library, running searches, uploading CSV files, and viewing the corpus knowledge map. Built with React, Vite, TanStack Query, and shadcn/ui. In production it is served by nginx, which also reverse-proxies
/api to the API container.API — Java 25 + Spring Boot
The sole public entry point. Validates all input, calls the Inference Service for classification and embeddings, persists results to Oracle via JPA and JDBC, and exposes every REST endpoint consumed by the web. The only layer that touches the database.
Inference Service — Python 3.12 + FastAPI
A stateless service that loads a single model artifact (
model.joblib) from OCI Object Storage on startup. Provides /predict for full content classification and /embed for query vectorization. Never touches the database.Oracle Autonomous Database
Stores every content record including a
VECTOR(384) column for semantic similarity. Nearest-neighbor queries run directly in the database engine using VECTOR_DISTANCE(COSINE), so the full indexed corpus participates in every search without a separate ranking service.System Diagram
Content Ingestion Flow
When a user submits a new document viaPOST /content, the following sequence occurs:
{
"title": "Introducción a Spring Boot",
"body": "En este contenido se presentan los conceptos básicos para crear APIs REST con Java y Spring Boot."
}
The API forwards only the
body field to the Inference Service’s POST /predict endpoint. The title is not sent — the classifier works on content, not metadata.The Inference Service applies the E5
"passage: " prefix internally, encodes the text with intfloat/multilingual-e5-small (384 dimensions), builds the 884-feature vector for the LogisticRegression classifier, and returns everything the API needs in a single response:{
"category": "Backend",
"probability": 0.89,
"keywords": ["java", "spring", "rest"],
"explanation": ["spring", "rest", "endpoint"],
"embedding": [0.021, -0.118, "…384 floats…"],
"cluster_id": 3,
"x": 4.21,
"y": -1.07
}
A single call to
/predict covers the entire indexing pipeline. Calling a separate embeddings endpoint for the same text would run the encoder twice — the most computationally expensive step — for no additional information. The cluster_id and UMAP coordinates (x, y) are also computed here, inside the artifact’s kmeans and umap_reducer objects, which the Java API cannot access directly.id, title, body, category, probability, keywords, cluster_id, x, y, added_at).embedding column using a raw UPDATE statement with the 384-float array cast to VECTOR(384, FLOAT32).Immediately after insertion, the API queries Oracle to find the five most semantically similar documents already in the corpus:
SELECT id, title, category,
1 - VECTOR_DISTANCE(embedding, :qv, COSINE) AS similarity
FROM contents
WHERE id <> :base_id
ORDER BY VECTOR_DISTANCE(embedding, :qv, COSINE)
FETCH FIRST :n ROWS ONLY
Semantic Search Flow
GET /search?mode=semantic follows a similar but lighter path:
The query string is sent to
POST /embed with type: "query". The type field is mandatory with no default — the E5 model requires the "query: " prefix when vectorizing search queries and "passage: " when indexing documents. Mixing them silently degrades search quality without raising any error.Port Reference
| Service | Port | Notes |
|---|---|---|
| API | 8080 | Published to host (ports: "8080:8080"); accessible directly during development |
| Inference | 8000 | Internal only (expose: "8000"); not published to host — only the API calls it |
| Web (dev) | 5173 | Vite dev server; proxies to API at http://localhost:8080 by default |
| Web (prod) | 80 | nginx container (enabled with --profile web); reverse-proxies /api to the API |
Scaffold Mode
The API is designed to start without any database connection. By default,application.properties excludes DataSourceAutoConfiguration and HibernateJpaAutoConfiguration via spring.autoconfigure.exclude, so the application boots with no JDBC driver, no connection pool, and no JPA context:
GET /contents, GET /search, POST /content, etc.) return 503 Service Unavailable. Endpoints that do not touch the database — such as GET /health and inference-proxying routes — continue to function normally.
The db profile re-enables the excluded auto-configurations and requires the three datasource variables (SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD) and TNS_ADMIN to be present. Docker Compose always starts the api container with SPRING_PROFILES_ACTIVE=db.
GET /health always returns 200 OK in both modes. In scaffold mode the database dependency is reported as enabled: false and the overall status is UP as long as the Inference Service is reachable. In db mode, the health controller probes Oracle with SELECT 1 FROM DUAL on a 3-second timeout using Java virtual threads — a timed-out probe marks the dependency reachable: false without taking down the endpoint.Explore Further
Deployment Overview
Run Mindloom on an OCI Ampere A1 VM with nginx and the full web profile.
Inference Service
Understand the model artifact, E5 prefixes, feature construction, and the embedding vs. features distinction.
POST /content
Full reference for the ingestion endpoint, including request/response schema and error codes.
Quickstart
Get all four layers running locally in under 5 minutes.