Skip to main content

What is Kandra

Kandra is an ERP/business-application engine for .NET (C# / EF Core / Blazor / Avalonia). It reimagines the domain abstractions that 1C:Enterprise and Odoo built their success on — Documents, Dictionaries, Registers, Reports — using modern C# idioms and AI-native tooling, rather than a bespoke scripting language or a Python ORM layered on a generic web framework.

If you've configured 1C or built modules on Odoo, the concepts here will feel familiar. If you haven't, think of Kandra as a framework where the shape of a business object (does it post transactions? does it hold reference data? is it a read-only report?) determines a fixed set of pieces you implement, and the framework generates everything else — REST controllers, client DI wiring, EF Core configuration, and (for several entity kinds) the Blazor UI itself.

The two things in this repo family

  • Kandra (the platform) — the reusable engine, consumed as a set of libraries. This is what you reference from a new configuration project; you don't fork it.
  • KandraWms ("Kandra WMS") — the first reference configuration built on the platform: a real warehouse-management domain plus a chart-of-accounts posting subsystem. It exists to prove the engine works end-to-end for a real domain, and it's the codebase this documentation site's practical guides constantly point at for working examples.

A configuration, in Kandra terms, is your own KandraWms-shaped project: a set of Dictionaries/Documents/Registers/Reports that model your business domain, built by referencing the Kandra platform libraries the same way KandraWms does. In practice you don't hand-build that shape — you scaffold it with a dotnet new template that produces an empty, buildable project referencing the platform purely via NuGet packages, with no platform source checkout required. See How to start.

The entity type system — the core abstraction

Every business object you build is one of seven kinds, each with a fixed capability profile:

KindPosts/submits?Has UI/form?Typical use
DocumentYesYesTransactional records — waybills, invoices, transfers. Writes registers and postings only inside OnSubmitAsync.
DictionaryNoYesReference/master data — items, warehouses, counterparties. Optional hierarchy.
ReportNoYes (generated)Parameterized, read-only queries over registers/documents.
DataProcessorNoYes (transient)A batch-operation form that isn't itself persisted.
RegisterNoAnalytical storage (balances, turnovers, info records) written only by document behaviors.
ConstantNoAdmin UI onlyA single scalar configuration value.
EnumNoA plain C# enum, used like any other .NET enum but integrated into the generated UI/print layer.

Every form-bearing kind (Document/Dictionary/Report/DataProcessor) is built from the same four pieces, split across two planes — server-only and client+server shared:

  1. *Base entity — the pure EF Core model. No UI or auth attributes.
  2. *Dto — the attribute-rich contract the generators read to emit controllers, client DI wiring, and generated UI.
  3. *Behavior — lifecycle hooks (OnNewAsync, OnBeforeSaveAsync, OnSubmitAsync, ...).
  4. *Validator — shared client+server validation, mandatory even if it just delegates to the base implementation.

You'll build all four, in that shape, for nearly everything you add. The Creating a dictionary and Creating a document guides walk through this concretely.

Why generators, not a scripting language

1C and Odoo both solve "don't repeat yourself across form/API/storage" with a dynamic runtime metadata layer or a scripting language. Kandra solves the same problem with Roslyn source generators: you write a strongly-typed C# *Dto with attributes, and the generator emits real C# — a real controller, real DI registration, a real EF Core configuration — into a Generated.Net/ folder you can read (but must never hand-edit). This means:

  • Full IntelliSense and compile-time checking on generated code, because it is checked-in compilable C#, not a runtime-interpreted script.
  • No separate "recompile the metadata layer" step — a normal dotnet build regenerates everything.
  • AI coding assistants (this documentation exists partly for that reason) can read generated output directly to understand what a Dto attribute actually produces, instead of having to simulate a scripting runtime.

Where to go next