# Key Data Models in Project N.O.M.A.D.'s Database: Complete Schema Guide

> Explore Project N.O.M.A.D.'s core AdonisJS Lucid models. Understand the database schema for managing microservices, content, LLM chats, and benchmark data in this comprehensive guide. Your complete schema overview awaits.

- Repository: [Crosstalk Solutions/project-nomad](https://github.com/Crosstalk-Solutions/project-nomad)
- Tags: api-reference
- Published: 2026-03-16

---

**Project N.O.M.A.D. persists its operational state across nine core AdonisJS Lucid models—Service, WikipediaSelection, KVStore, InstalledResource, CollectionManifest, ChatSession, ChatMessage, BenchmarkSetting, and BenchmarkResult—that manage Docker microservices, content installations, LLM conversations, and hardware benchmarking data.**

Project N.O.M.A.D. (Nomad Operating Machine-Assisted Data-store) is an open-source platform that orchestrates offline-capable services through Docker-based microservices. The application layer stores all operational state, user content selections, and system metrics in a relational database accessed through AdonisJS Lucid ORM models located in `admin/app/models`. Understanding these **key data models used in Project N.O.M.A.D.'s database** is essential for developers extending the platform or integrating with its API.

## Service Model: Managing Docker Microservice Dependencies

The `Service` model (defined in [`admin/app/models/service.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/service.ts)) represents every containerized microservice that Nomad can install or manage.

### Self-Referential Dependency Graphs

This model implements a dependency tree through self-referential relationships. The `dependency` field establishes a `belongsTo` relationship to another Service, while `dependencies` provides a `hasMany` inverse. This allows Nomad to resolve installation order when services rely on others (e.g., a database container required by an application).

### Key Service Attributes

Notable columns include `service_name`, `container_image`, `installed` (boolean flag), `ui_location` (where the service UI is exposed), and `metadata` (JSON configuration). When a user enables a service, the `installed` flag transitions to `true` and `available_update_version` may populate if updates exist.

```typescript
// Fetch installed services with their dependency chains
import Service from '#models/service'

const services = await Service.query()
  .where('installed', true)
  .preload('dependencies')

```

## Content Management Models: ZIM Files and Map Resources

Project N.O.M.A.D. manages offline content through three interconnected models that track downloadable resources.

### WikipediaSelection

The `WikipediaSelection` model ([`admin/app/models/wikipedia_selection.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/wikipedia_selection.ts)) tracks the lifecycle of Wikipedia ZIM files selected for download. Key fields include `option_id` (unique identifier), `url` (source location), `filename`, and `status`—which follows a state machine of `none`, `downloading`, `installed`, or `failed`.

```typescript
import WikipediaSelection from '#models/wikipedia_selection'

const selection = await WikipediaSelection.findBy('option_id', 'enwiki-20240101')
if (selection) {
  selection.status = 'installed'
  await selection.save()
}

```

### InstalledResource

Once downloaded, physical files are recorded in `InstalledResource` ([`admin/app/models/installed_resource.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/installed_resource.ts)). This model distinguishes between resource types via the `resource_type` enum (`zim` or `map`), storing `file_path`, `version`, and `installed_at` timestamps. It bridges the gap between logical selections and actual filesystem assets.

### CollectionManifest

To avoid repeated network requests, `CollectionManifest` ([`admin/app/models/collection_manifest.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/collection_manifest.ts)) caches remote catalog metadata. The `type` field (typed as `ManifestType`), `spec_version`, and `spec_data` (JSON blob) store Kiwix or map catalog information with `fetched_at` timestamps for cache invalidation.

## Configuration Storage: The KVStore Model

For application settings that don't warrant dedicated tables, the `KVStore` model ([`admin/app/models/kv_store.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/kv_store.ts)) provides a type-safe key-value interface. The `key` field adheres to `KV_STORE_SCHEMA` for type safety, while `value` stores stringified data.

Static helper methods simplify access:

```typescript
import KVStore from '#models/kv_store'

await KVStore.setValue('ui_theme', 'dark')
const theme = await KVStore.getValue('ui_theme') // Returns 'dark'

```

This pattern supports UI preferences, API keys, and feature flags without schema migrations.

## Conversational AI: ChatSession and ChatMessage

The platform's built-in LLM assistant persists conversations through two related models.

### ChatSession

`ChatSession` ([`admin/app/models/chat_session.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/chat_session.ts)) represents a top-level conversation, storing `title` and the `model` identifier (e.g., 'llama.cpp'). It maintains a `hasMany` relationship to individual messages.

### ChatMessage

`ChatMessage` ([`admin/app/models/chat_message.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/chat_message.ts)) contains the actual conversation content with `role` enums (`system`, `user`, `assistant`) and `content` text. The `session_id` foreign key establishes the `belongsTo` relationship back to the parent session.

```typescript
import ChatSession from '#models/chat_session'
import ChatMessage from '#models/chat_message'

const session = await ChatSession.create({ 
  title: 'Nomad Help', 
  model: 'llama.cpp' 
})

await ChatMessage.create({
  session_id: session.id,
  role: 'user',
  content: 'How do I add a new map?'
})

```

## Performance Benchmarking: BenchmarkSetting and BenchmarkResult

The "NOMAD Score" feature relies on two models that configure and store hardware performance metrics.

### BenchmarkSetting

`BenchmarkSetting` ([`admin/app/models/benchmark_setting.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/benchmark_setting.ts)) stores configuration values for the benchmark subsystem. The `key` field uses the `BenchmarkSettingKey` enum (e.g., controlling anonymous submission preferences), with corresponding `value` storage.

### BenchmarkResult

`BenchmarkResult` ([`admin/app/models/benchmark_result.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/benchmark_result.ts)) persists comprehensive performance data including `cpu_score`, `memory_score`, `disk_read_score`, `disk_write_score`, and `ai_tokens_per_second`. The composite `nomad_score` aggregates these metrics into a single performance rating, while `submitted_to_repository` tracks whether results were shared upstream.

```typescript
import BenchmarkResult from '#models/benchmark_result'

await BenchmarkResult.create({
  benchmark_id: 'run-2024-03-01',
  benchmark_type: 'hardware',
  cpu_model: 'Intel i7-12700K',
  cpu_cores: 12,
  ram_bytes: 32_000_000_000,
  disk_type: 'ssd',
  cpu_score: 8450,
  memory_score: 7200,
  disk_read_score: 1500,
  nomad_score: 88,
  submitted_to_repository: false,
})

```

## Common Model Architecture

All models inherit from `BaseModel` and utilize `SnakeCaseNamingStrategy`, ensuring database columns use snake_case (e.g., `created_at`, `updated_at`). Timestamps are automatically managed via the `@column.dateTime({ autoCreate: true, autoUpdate: true })` decorator, eliminating manual date handling.

## Summary

- **Service** models manage Docker microservices with self-referential dependency graphs for installation ordering.
- **WikipediaSelection** and **InstalledResource** track the lifecycle of offline content from download queue to filesystem storage.
- **CollectionManifest** caches remote catalog metadata to minimize network requests.
- **KVStore** provides type-safe key-value storage for miscellaneous application settings.
- **ChatSession** and **ChatMessage** implement conversational logging for the LLM assistant.
- **BenchmarkSetting** and **BenchmarkResult** support the NOMAD Score feature with detailed hardware and AI performance metrics.
- All models reside in `admin/app/models` and leverage AdonisJS Lucid ORM conventions with automatic timestamp management.

## Frequently Asked Questions

### What ORM does Project N.O.M.A.D. use for its database models?

Project N.O.M.A.D. uses **AdonisJS Lucid**, an ActiveRecord-style ORM that provides the `BaseModel` class inherited by all data models. This ORM handles query building, relationships, and timestamp management automatically.

### How does the Service model handle dependencies between Docker containers?

The `Service` model implements **self-referential relationships** through `belongsTo` (dependency) and `hasMany` (dependencies) associations defined in [`admin/app/models/service.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/models/service.ts). This allows the system to resolve installation order by traversing the dependency graph before starting containers.

### Where are the database models located in the Project N.O.M.A.D. repository?

All TypeScript model files are located in the `admin/app/models/` directory, with each model typically named after its entity (e.g., [`service.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/service.ts), [`kv_store.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/kv_store.ts), [`benchmark_result.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/benchmark_result.ts)). They follow AdonisJS conventions using snake_case database columns via `SnakeCaseNamingStrategy`.

### What is the difference between WikipediaSelection and InstalledResource?

**WikipediaSelection** tracks the user's intent to download specific ZIM files and manages download states (`downloading`, `installed`, etc.), while **InstalledResource** records the actual physical files present on the host system, including file paths and versions for both ZIM and map resources.