Skip to content

Developer Guide

Whether you’re building a search experience on top of Viglet Turing or contributing to the project itself, this guide has everything you need to get up and running quickly.

Turing is a fully open-source enterprise search platform with semantic navigation and GenAI capabilities. The source code lives at github.com/openviglet/turing and all contributions are welcome.


Understanding the stack helps you navigate the codebase and decide where to plug in.

LayerTechnology
BackendJava 21 · Spring Boot · Spring AI
Search EngineApache Solr (primary) · Elasticsearch · Lucene
Message QueueApache Artemis
DatabaseH2 (dev) · PostgreSQL / MySQL (prod)
FrontendReact · TypeScript · shadcn/ui · Vite
AI / GenAISpring AI · ChromaDB · PgVector · Milvus
BuildMaven (backend) · npm (frontend)
CI/CDGitHub Actions
%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '13px', 'primaryColor': '#fff', 'primaryBorderColor': '#c0c0c0', 'lineColor': '#888', 'textColor': '#333'}}}%%
graph TD
A["💻 Your IDE"] -->|"mvn spring-boot:run"| B["☕ Turing Backend\nSpring Boot / Java 21"]
A -->|"npm run dev"| C["⚛️ React Admin Console\nlocalhost:5173"]
B --> D["🔎 Apache Solr\nlocalhost:8983"]
B --> E["📨 Apache Artemis\nMessage Queue"]
C -->|"REST API"| B
classDef blue fill:#dbeafe,stroke:#4A90D9,stroke-width:2px,color:#1a1a1a
classDef green fill:#dcfce7,stroke:#50B86C,stroke-width:2px,color:#1a1a1a
classDef purple fill:#ede9fe,stroke:#9B6EC5,stroke-width:2px,color:#1a1a1a
classDef amber fill:#fef3c7,stroke:#E8A838,stroke-width:2px,color:#1a1a1a
class A amber
class B,E purple
class C blue
class D green

Before you begin, make sure you have these installed:

Terminal window
git clone https://github.com/openviglet/turing.git
cd turing

Apache Solr is the only external service required to run Turing. Apache Artemis runs embedded inside the application and requires no separate installation. The easiest way to start Solr locally is with Docker Compose:

Terminal window
docker-compose up -d

This starts:

  • Apache Solr at http://localhost:8983

Run the full backend including the bundled React console:

Terminal window
cd turing
mvn spring-boot:run -pl turing-app

Or skip the npm build step if you haven’t changed the frontend:

Terminal window
mvn spring-boot:run -pl turing-app -Dskip.npm

The backend starts at http://localhost:2700.

For active frontend development, run the React dev server separately. First start the backend in headless mode:

Terminal window
mvn spring-boot:run -pl turing-app -Dskip.npm -Dspring-boot.run.profiles=dev-ui

Then launch the React app:

Terminal window
cd turing/turing-ui
npm install
npm run dev

The Vite dev server starts at http://localhost:5173 with hot-reload enabled.

Terminal window
cd turing
mvn clean install
mvn package -pl turing-app

The resulting JAR in turing-app/target/ bundles both the backend and the compiled React assets.


ServiceURLNotes
Admin Consolehttp://localhost:2700Backend-served
React Dev Serverhttp://localhost:5173Vite hot-reload
SN Search Samplehttp://localhost:2700/sn/Sample
Swagger UIhttp://localhost:2700/swagger-ui.htmlInteractive API docs
OpenAPI Spechttp://localhost:2700/v3/api-docsJSON spec
Solrhttp://localhost:8983Docker Compose

The Turing Java SDK lets you integrate semantic search into any JVM application.

Terminal window
cd turing-java-sdk
mvn package
java -cp build/libs/turing-java-sdk-all.jar com.viglet.turing.client.sn.sample.TurSNClientSample

Add to your pom.xml:

<dependency>
<groupId>com.viglet.turing</groupId>
<artifactId>turing-java-sdk</artifactId>
<version>2026.2.4</version>
</dependency>

The SDK and turing-commons are published to Maven Central. No custom repository configuration is needed.

Terminal window
cd turing-java-sdk
mvn package

Turing uses Liquibase (v5.0.2) for database schema management. All schema changes (tables, columns, indexes, foreign keys) are tracked as versioned changelogs and applied automatically on startup. This ensures every environment (dev, staging, production) runs the exact same schema, regardless of the database platform.

When Turing starts, Spring Boot runs Liquibase before the application context is fully initialized. Liquibase reads the master changelog, compares it against the DATABASECHANGELOG tracking table, and applies any pending changesets. This means:

  • First startup: all migrations run, creating the full schema from scratch
  • Upgrades: only new changesets (added since the last startup) are applied
  • Rollbacks: changesets already applied are skipped (DATABASECHANGELOG tracks what has run)

Liquibase is configured in application.yaml:

spring:
liquibase:
change-log: classpath:db/changelog/db.changelog-master.yaml
enabled: true
default-schema: PUBLIC

All changelogs are in YAML format under turing-app/src/main/resources/db/changelog/:

db/changelog/
├── db.changelog-master.yaml ← master file, includes all others
├── v2025.3_baseline.yaml ← initial schema (full baseline)
├── v2026.1_update.yaml ← major version update
├── v2026.1_type_enum_fix.yaml ← type/enum corrections
├── v2026.1.11.yaml ← incremental patch
├── v2026.1.11.1.yaml ← incremental patch
├── v2026.1.12.yaml ← incremental patch
├── v2026.1.14.0.yaml ← incremental patch
├── v2026.1.14.1.yaml ← ...
├── ...
└── v2026.1.14.8.yaml

The master changelog (db.changelog-master.yaml) includes all files in sequential order:

databaseChangeLog:
- include:
file: db/changelog/v2025.3_baseline.yaml
- include:
file: db/changelog/v2026.1_update.yaml
- include:
file: db/changelog/v2026.1_type_enum_fix.yaml
- include:
file: db/changelog/v2026.1.11.yaml
# ... incremental patches follow
PatternExampleUsage
v{version}_baseline.yamlv2025.3_baseline.yamlFull schema baseline for a major version
v{version}_update.yamlv2026.1_update.yamlGenerated diff between two versions
v{version}.yamlv2026.1.12.yamlIncremental patch for a specific release

When adding a new table, column, or index, create a new changelog file following the naming convention and add it to the master changelog.

Example, adding a column to an existing table:

databaseChangeLog:
- changeSet:
id: v2026.1.15-01-add-priority-to-spotlight
author: viglet-team
preConditions:
- onFail: MARK_RAN
- tableExists:
tableName: sn_site_spotlight
- not:
- columnExists:
tableName: sn_site_spotlight
columnName: priority
changes:
- addColumn:
tableName: sn_site_spotlight
columns:
- column:
name: priority
type: INT
defaultValueNumeric: 0

Key rules:

  • Always use preconditions with onFail: MARK_RAN to make changesets idempotent: safe to re-run if the change was already applied manually
  • Changeset IDs use the format v{version}-{sequence}-{description} (e.g., v2026.1.14-01-add-default-label-to-custom-facet)
  • Authors use viglet-team for manual migrations or {name} (generated) for auto-generated diffs
  • Never modify an already-released changeset: always create a new one

The Liquibase Maven plugin can auto-generate a diff between two database versions:

Terminal window
cd turing-app
mvn liquibase:diff

This compares the reference database (current code) against the target database (previous version) and writes a changelog to src/main/resources/db/changelog/v2026.1_update.yaml. The diff tracks: tables, columns, indexes, foreign keys, and primary keys.

The plugin configuration is in turing-app/pom.xml and uses liquibase.properties for connection settings.

Liquibase abstracts SQL differences across platforms. The same changelogs work on all supported databases:

DatabaseDriverNotes
H2org.h2.DriverDefault for development: embedded, zero setup
MariaDB / MySQLorg.mariadb.jdbc.DriverProduction recommended
PostgreSQLorg.postgresql.DriverProduction recommended
Oracleoracle.jdbc.OracleDriverEnterprise environments
SQL Servercom.microsoft.sqlserver.jdbc.SQLServerDriverEnterprise environments

Liquibase handles type mappings (e.g., VARCHAR(255) on MySQL vs VARCHAR2(255) on Oracle) transparently.


Turing maintains high code quality standards. You can check the project health at any time:

ToolLink
SonarCloudsonarcloud.io/organizations/viglet-turing
GitHub Actionsopenviglet/turing/actions
GitHub Securityopenviglet/turing/security

Turing uses a plugin architecture to support multiple search backends behind a unified interface. This abstraction allows the same application code to work with Apache Solr, Elasticsearch, or Lucene: the active plugin is resolved at runtime based on the vendor configured per Search Engine instance.

%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '13px', 'primaryColor': '#fff', 'primaryBorderColor': '#c0c0c0', 'lineColor': '#888', 'textColor': '#333'}}}%%
graph TD
FACTORY["⚙️ TurSearchEnginePluginFactory\n(resolves by vendor, fallback → Solr)"]
SOLR["🔎 TurSolrSearchEnginePlugin"]
ES["🔎 TurElasticsearchSearchEnginePlugin"]
LUCENE["🔎 TurLuceneSearchEnginePlugin"]
FACTORY --> SOLR
FACTORY --> ES
FACTORY --> LUCENE
classDef purple fill:#ede9fe,stroke:#9B6EC5,stroke-width:2px,color:#1a1a1a
classDef green fill:#dcfce7,stroke:#50B86C,stroke-width:2px,color:#1a1a1a
class FACTORY purple
class SOLR,ES,LUCENE green

All backend operations are defined in a single interface with four categories:

Search

MethodDescription
retrieveSearchResults()Execute a full-text query and return results with facets
retrieveFacetResults()Return facet counts for a query

Index management

MethodDescription
createIndex()Create a new core / index
deleteIndex()Delete a core / index
clearIndex()Remove all documents from a core without deleting it
listIndexes()List all cores / indices on the backend

Schema management

MethodDescription
addOrUpdateField()Add or update a field definition in the schema
deleteField()Remove a field from the schema
fieldExists()Check whether a field exists in the schema

Documents & monitoring

MethodDescription
indexDocument()Index a single document
deIndex()Remove a document from the index
commit()Flush pending writes (for backends that require explicit commits)
getDocumentTotal()Return the total number of indexed documents
getSystemInfo()Return backend version, OS, JVM, and memory information

To add support for a new search engine:

  1. Create a class implementing TurSearchEnginePlugin
  2. Implement all methods in the four categories above
  3. Register the plugin in TurSearchEnginePluginFactory with a vendor identifier
  4. The factory resolves the correct plugin based on the vendor field of the TurSEInstance entity

Turing exposes a REST API for integrating search and AI capabilities into any application. All endpoints use JSON. Authentication uses the Key header with an API Token created in Administration → API Tokens.

For the full endpoint reference (search, autocomplete, spell check, latest searches, GenAI chat, and token usage) see REST API Reference.

For interactive exploration, use the built-in Swagger UI at http://localhost:2700/swagger-ui.html or the OpenAPI spec at http://localhost:2700/v3/api-docs.


We’d love your help making Turing better. Here’s how to get involved:

  1. Fork the openviglet/turing repository.
  2. Create a branch for your feature or fix: git checkout -b feature/my-improvement
  3. Commit your changes with clear, descriptive messages.
  4. Open a Pull Request: describe what you changed and why.

For larger contributions, open an issue first to discuss the approach before writing code.


PageDescription
REST API ReferenceSearch, autocomplete, GenAI chat endpoints
GraphQLThe graph query endpoint
React SDKHeadless hooks + components for custom UIs
Client ToolsBuilding agent↔UI features against the chat SSE
Reference showcaseA full app built on the SDKs
Architecture OverviewThe system at a glance