Developer Setup¶
This tutorial walks you through cloning the repository, building the solution, running the test suite, and getting the Engine and Dashboard running locally. By the end you will have a working development environment and an understanding of where things live in the codebase.
Prerequisites¶
- .NET 10 SDK —
dotnet --versionshould report10.0.xor later. Download from dot.net. - Git —
git --versionto confirm. - Approximately 10 GB free disk space (AI models download on first Engine startup).
No other global tools are required. All project dependencies are declared in .csproj files and restored by the .NET toolchain.
Step 1 — Clone and branch¶
git clone https://github.com/shyfaruqi/tuvima-library.git
cd tuvima-library
git checkout -b feature/your-branch-name
The main branch is the integration target. All work goes on a feature branch.
Step 2 — Project structure overview¶
The solution is split into focused projects under src/ and tests/. Each project has a single responsibility:
| Project | Role |
|---|---|
src/MediaEngine.Domain |
Domain entities, interfaces, value objects. Pure business logic — no I/O dependencies. |
src/MediaEngine.Storage |
SQLite data access via Dapper. Repositories, migrations, and query logic. |
src/MediaEngine.Intelligence |
Priority Cascade engine. Scores and resolves metadata claims. |
src/MediaEngine.Processors |
File processors — reads embedded metadata from EPUB, ID3 tags, video containers, etc. |
src/MediaEngine.Providers |
External provider adapters — Apple API, Google Books, TMDB, Wikidata Reconciliation API. |
src/MediaEngine.Ingestion |
Folder watcher, ingestion pipeline, file organiser, staging logic. |
src/MediaEngine.AI |
Local LLM and Whisper inference. Hardware profiling, model management, AI feature implementations. |
src/MediaEngine.Api |
ASP.NET Core host. HTTP endpoints, SignalR hub, background services. Exposes the Engine. |
src/MediaEngine.Web |
Blazor Server host. Dashboard UI — components, pages, services. |
tests/ |
xUnit test projects, one per domain area. |
The config/ directory holds all runtime configuration as individual JSON files (committed to git; provider secrets in config/secrets/, gitignored). The .data/ directory holds the SQLite database, cover art images, and staging files (gitignored).
Step 3 — Configuration¶
Configuration files are already in the repository. Add secret files for any providers that require API keys (e.g. config/secrets/tmdb.json with {"api_key": "your-key"}).
The key file is config/core.json. The defaults work without modification for local development:
Other config files of interest during development:
| File | Purpose |
|---|---|
config/ai.json |
AI model paths, hardware tier overrides, feature flags |
config/libraries.json |
Watch folders (add entries here to seed a dev library) |
config/scoring.json |
Priority Cascade weights and tier configuration |
config/providers/*.json |
Per-provider settings (endpoints, API keys, language strategy) |
config/hydration.json |
Hydration pipeline slot configuration |
Sensitive values (API keys for external providers) go in config/providers/*.json. These files are gitignored — never commit them.
Step 4 — Build¶
From the repository root:
The build must produce 0 errors and 0 warnings. If warnings appear, treat them as errors — the CI pipeline enforces this. Investigate and fix before proceeding.
If you see NU1101 package restore errors, check your NuGet source configuration. The Tuvima.WikidataReconciliation package is published to the project's private NuGet feed; ensure your NuGet.Config points to it.
Step 5 — Run tests¶
All tests must pass before committing. Test projects mirror the src/ structure:
tests/
MediaEngine.Domain.Tests/
MediaEngine.Storage.Tests/
MediaEngine.Intelligence.Tests/
MediaEngine.Processors.Tests/
MediaEngine.Providers.Tests/
MediaEngine.Ingestion.Tests/
To run a specific project:
To run with coverage:
Coverage reports are written to TestResults/ inside each test project.
Step 6 — Start the Engine¶
The Engine starts on http://localhost:61495. On first run it will:
- Run a hardware benchmark (10–30 seconds).
- Apply any pending SQLite migrations automatically.
- Start the folder watcher for any configured library folders.
- Begin downloading AI models in the background (~9 GB total).
The Engine is ready when you see:
To run without AI model downloads (useful for UI-only development):
Step 7 — Start the Dashboard¶
Open a second terminal:
The Dashboard starts on http://localhost:5016. Open it in your browser.
Hot reload is available during development:
This rebuilds and refreshes the browser on file saves. Note: Blazor Server hot reload works best for component changes. Changes to DI registrations, middleware, or static assets may require a full restart.
Step 8 — Swagger / interactive API explorer¶
With the Engine running, open:
This shows all Engine endpoints, organised by controller. You can send requests directly from the browser — useful for testing endpoint behaviour without writing test code.
The Swagger UI is generated automatically from XML doc comments on controller methods. Keep doc comments up to date when adding or modifying endpoints.
Step 9 — Key conventions¶
Headless design: Engine and Dashboard are strictly separated¶
The Dashboard never imports types from Engine projects. All data flows via HTTP (REST) and SignalR. The contract lives in:
src/MediaEngine.Web/Services/Integration/ILibraryApiClient.cs— interface for all Engine callssrc/MediaEngine.Web/Services/Integration/LibraryApiClient.cs— implementation (maps JSON responses to view DTOs)src/MediaEngine.Web/Models/ViewDTOs/— data shapes used only by the Dashboard
Never add a project reference from MediaEngine.Web to any Engine project.
Feature-Sliced Dashboard layout¶
Dashboard code is organised by feature slice, not by technical layer. When adding new UI code, put it in the correct slice:
| Code type | Location |
|---|---|
| Engine HTTP call | Services/Integration/LibraryApiClient.cs + interface |
| Dashboard data shape | Models/ViewDTOs/ |
| Reusable component | Components/<FeatureName>/ |
| Full page (routed) | Components/Pages/ |
| Vault sub-component | Components/Vault/ |
| Settings tab | Components/Settings/ |
See CLAUDE.md §6 for the full layout reference.
SQLite with Dapper¶
The data access layer uses Dapper (not Entity Framework). SQL queries are written by hand in repository classes under src/MediaEngine.Storage/Repositories/. Migrations are numbered sequentially (M-001, M-002, …) and applied automatically at startup by MigrationRunner.
When adding a new column or table:
1. Create a new migration file in src/MediaEngine.Storage/Migrations/.
2. Number it one above the current highest migration.
3. Register it in MigrationRunner.cs.
4. Never modify an existing migration that has been applied to production.
Zero warnings policy¶
The solution sets <TreatWarningsAsErrors>true</TreatWarningsAsErrors> in Directory.Build.props. New code must be warning-free. This includes nullable reference type warnings — all new code must be null-safe.
Step 10 — Where to find things¶
Engine endpoints live in src/MediaEngine.Api/Endpoints/. Each file groups related actions (e.g., LibraryEndpoints.cs, VaultEndpoints.cs, AiEndpoints.cs). Endpoints use minimal API style (MapGet, MapPost, etc.) registered in Program.cs.
Domain entities live in src/MediaEngine.Domain/Entities/. The core hierarchy: MediaAsset → Edition → Work → Hub (Series) → ParentHub (Universe).
Dashboard components live in src/MediaEngine.Web/Components/. Navigation is in Components/Navigation/, Vault in Components/Vault/, Settings in Components/Settings/.
Background services live in src/MediaEngine.Api/Services/. Long-running services (ingestion watcher, hydration scheduler, AI batch processor) are registered as IHostedService implementations.
Provider adapters live in src/MediaEngine.Providers/Adapters/. Each adapter implements IMetadataProvider. The ReconciliationAdapter handles all Wikidata interaction.
AI features live in src/MediaEngine.AI/Features/. Each feature is a focused service (e.g., SmartLabeler, VibeTagger, QidDisambiguator, DescriptionIntelligenceService).
Commit conventions¶
Commits follow this format:
Short summary line (imperative mood, 72 chars max)
Optional longer body explaining why, not what.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The build must pass before committing. Run dotnet build and dotnet test and confirm 0 errors before pushing.
Next steps¶
- Read the architecture deep-dives for the subsystem you are working on.
- Check
CLAUDE.mdfor project conventions and vocabulary rules. - Check
MEMORY.mdfor recorded architectural decisions. - Use
http://localhost:61495/swaggerto explore the Engine's action surface while reading endpoint code.