Skip to content

Architecture Overview

Fullfinity is a modular business application platform built on modern async Python.

┌─────────────────────────────────────────────────────────────┐
│ Frontend │
│ (React + Mantine UI) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ REST API Layer │
│ (FastAPI) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Auto CRUD │ │ Method Exec │ │ Action/View Builder │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ ORM Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Models │ │ Fields │ │ Query Builder │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Cache │ │ Security │ │ Computed │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Database Layer │
│ ┌─────────────────────────┐ ┌────────────────────────┐ │
│ │ PostgreSQL (asyncpg) │ │ Valkey/Redis Cache │ │
│ └─────────────────────────┘ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

The query-intelligent ORM — designed to eliminate wasted work:

  • Selective Hydration - Request 5 fields, fetch 5 fields
  • Smart Calculated Fields - Each calculation loads only its specific dependencies
  • Intelligent Prefetching - Related records batched automatically, no N+1
  • One Expression Language - Q() syntax works in Python, views, security rules, and client-side
  • True Async - Native async throughout, not a wrapper
  • Identity Map - One instance per record within a request; repeat reads reuse it

See ORM Design Philosophy for the full story.

Each module is a self-contained unit:

modules/
├── core/ # Base module (required)
├── crm/ # CRM functionality
├── invoicing/ # Invoicing & accounting
├── inventory/ # Stock management
└── your_module/ # Your custom modules

YAML-based declarative views:

  • Form Views - Detail/edit forms
  • List Views - Data tables
  • Kanban Views - Card-based views
  • Calendar Views - Timeline views
  • Search Views - Filters and groupings

Role-based access control:

  • Groups - User permission groups
  • Model Access - CRUD permissions per model
  • Record Rules - Row-level security

Connects views to data:

  • Window Actions - Define which views show for a model
  • Menus - Navigation structure
  • View Resolution - Inheritance and composition
1. HTTP Request
2. FastAPI Router
3. Authentication/Authorization Check
4. Action Builder (load views, resolve inheritance)
5. ORM Query (with caching)
6. Security Filters (record rules)
7. Serialization
8. HTTP Response

Opening a screen used to cost two requests: one for the screen’s definition (its views, their composed layouts, the model’s field metadata, the search view) and one for the records. The definition is metadata, so the client keeps it and re-uses it — a navigation costs one request, for the rows.

Every response carries the header X-Ui-Version, a per-database stamp of everything that can change what a screen renders. While it is unchanged the client serves its stored copy with no request at all; when it moves, the next navigation refetches. The stamp advances on a module install, upgrade or uninstall, on a permissions change, on a settings change (a setting can gate a menu or a field through visible_setting), and on a write to any record the screen definition is built from — a menu, a view, a window or report action, a saved filter. The navigation menu is cached the same way, so a warm boot renders it without a request.

If you add a model whose records change what a screen renders, bump the stamp from its write path, or users will keep seeing the previous version until something else moves it:

from fullfinity.engine.cache_version import bump_ui_metadata_version
class MyScreenRule(Model):
async def update(cls, records, **vals):
result = await super().update(records, **vals)
await bump_ui_metadata_version()
return result

It is bumped inside your write transaction, so it commits atomically with the change it signals. Ordinary business records need nothing — a sale order changing must not invalidate every browser’s screen definitions.

Two things are handled for you and are not in the stamp: the user’s language (screens are translated as they are composed, so the client drops its stored copies when the language changes) and configuration gating (visible_setting is resolved per request, never cached), so a setting toggled in one company is never served to another.

All database operations are async using asyncpg:

# Non-blocking I/O
users = await User.filter(active=True).all()

Views are defined in YAML for:

  • Concise, readable authoring
  • Better tooling support
  • Easy diffing of layout changes

View inheritance uses semantic targeting:

target:
field: name # Not arch[0].content[1]

Every model is reachable through generic, model-name-parameterized endpoints ({class_name} is the model name):

  • POST /api/create/{class_name} - Create
  • POST /api/fetch/{class_name}/{id} - Read one
  • POST /api/query/{class_name} - List/query with filters
  • PUT /api/update/{class_name}/{record_id} - Update
  • DELETE /api/delete/{class_name}/{id} - Delete
  • POST /api/execute/{class_name}/{method_name} - Call a model method

(Bulk variants — bulk-create, bulk-update, bulk-delete — also exist.)

Each tenant has its own PostgreSQL database for:

  • Data isolation
  • Independent module installation
  • Simplified backup/restore
fullfinity/
├── main.py # Application entry point
├── engine/ # Core framework / ORM implementation
│ ├── models.py # Base Model class + metaclass
│ ├── fields.py # Field type definitions
│ ├── db.py # Database manager
│ ├── env.py # Environment context (per-DB model registry)
│ ├── Q.py # Query objects
│ ├── cache.py # Cache manager
│ ├── module_registry.py # Manifest loading + load order
│ └── licensing/ # Enterprise gating
├── modules/ # Application modules
│ ├── core/ # Core module
│ └── ... # Other modules
└── app/ # Frontend (React)