Fullfinity
A platform, not a locked box. Model your domain in Python, lay out screens in readable YAML, and extend any app cleanly — with an access-aware ORM underneath and customizations that keep working through every upgrade.
Fullfinity is an open-core Business OS. The open-source apps are Apache-2.0; the engine, ORM and React frontend are the platform you build on. Whether you deliver Fullfinity for clients or run your own in-house roadmap, you get the same stack — self-hosted or on our cloud.
Built to be extended
Section titled “Built to be extended”The core move is __inherit__: add fields, calculated values and logic to any existing
app without forking it or patching its source. Your extension is a normal module — it
installs, upgrades and uninstalls on its own, and it survives upgrades to the app it
extends.
# Extend any app — install a module, don't fork itfrom fullfinity.engine.base import *
class SaleOrder(Model): __inherit__ = "SaleOrder"
priority = Selection(["Normal", "Rush"], default="Normal")
@Model.calculate("lines", "lines__amount") async def calc_total(self): await self.fetch_related("lines") self.total = sum(l.amount for l in self.lines)Why Fullfinity?
Section titled “Why Fullfinity?”Most ORMs execute queries. Ours understands them — selective field hydration, smart calculated-field dependencies, automatic prefetching, and true async throughout.
| Aspect | What you get |
|---|---|
| ORM | Query-intelligent — fetches only the fields you touch |
| Calculated Fields | Dependency resolution per field, so a rollup doesn’t drag the whole graph in |
| Async | Native async throughout, on asyncpg |
| Views | Declarative YAML with semantic inheritance — extensions target named anchors, not positions |
| Frontend | React + Mantine, rendered from your YAML — no frontend code to write |
| Expression Language | The same Q() syntax in Python, YAML rules and security |
The stack, top to bottom
Section titled “The stack, top to bottom”Four layers, each built to extend — and the same stack whether you self-host or run on our cloud.
| Layer | Tech | What it gives you |
|---|---|---|
| Frontend | React + Mantine | 59+ widgets, dark mode and responsive layouts — forms, lists, kanban, calendar, gantt, charts and more, all rendered from YAML. No frontend code to write. |
| API | FastAPI | Async request handling, REST endpoints generated from your models, WebSocket push and OpenAPI docs. |
| ORM | Access-aware engine | Selective loading, automatic prefetch and stored calculated fields with dependency tracking. It writes the SQL so you don’t. |
| Database | PostgreSQL | JSONB for flexible data, full-text search and async pooling via asyncpg. |
Define once, get everything
Section titled “Define once, get everything”Write the model in Python and the framework handles the rest — the table, the migration, the REST API, and the data behind your screens. No ORM boilerplate, no hand-written migration files.
from fullfinity.engine.base import *
class Invoice(Model): _verbose_name = "Invoice"
customer = ManyToOne("Contact", related_name="invoices", on_delete="RESTRICT") date = Date(default=lambda self: date.today()) state = Selection(["Draft", "Posted"], default="Draft") total = Float(calculate="calc_total", store=True)
@Model.calculate("lines", "lines__amount") async def calc_total(self): await self.fetch_related("lines") self.total = sum(l.amount for l in self.lines)Lay out the screen in YAML — a 12-column grid of fields and widgets:
- data_type: UiView identifier: invoice_form_view type: Form model: Invoice arch: - type: row content: - type: column span: 6 content: - type: field name: customer properties: {widget: DataCombo} - type: field name: date properties: {widget: DatePickerInput} - type: column span: 6 content: - type: field name: state properties: {widget: Badge} - type: field name: total properties: {widget: Monetary}Composable, optimized queries
Section titled “Composable, optimized queries”Chain conditions with Q objects, traverse relationships with double-underscore
lookups, and select only the fields you touch. The engine generates efficient joins and
prefetches related records — so a list view isn’t a hundred round-trips. The same Q
syntax works in Python, in YAML view rules, and in widget filters.
# Composable filters — chained, then optimizedposted = await Invoice.filter( Q(state="Posted") & Q(total__gte=1000)).prefetch_related("customer", "lines").all()
# Traverse relationships — no extra queriesoverdue = await Invoice.filter( date__lt=today, customer__country__code="US").all()Open core, upgrade-safe
Section titled “Open core, upgrade-safe”The open-source apps are Apache-2.0 — read them, extend them, and publish your own to the built-in app store. Because extensions are modules and migrations are declarative, your customizations keep working through every upgrade instead of breaking on the next release.
Getting Started
Section titled “Getting Started”Documentation
Section titled “Documentation”- Architecture — how the ORM, modules and migrations work
- Models — define your data structures and calculated fields
- Views — lay out screens with the widget library
- Security — groups, model permissions and record rules
- Guides — step-by-step tutorials, including Custom Routes