---
name: backend
description: Guide for building backend features in Kantree including key architecture concepts and common patterns to use.
---
# Kantree Backend

## Table of Contents

- [Architecture Overview](#architecture-overview)
- [Code style guidelines](#code-style-guidelines)
- [Testing](#testing)
- [Application Bootstrap](#application-bootstrap)
- [Data Layer](#data-layer)
- [Actions](#actions)
- [Permissions System](#permissions-system)
- [KQL (Kantree Query Language)](#kql-kantree-query-language)
- [API Layer](#api-layer)
- [Signals & Events](#signals--events)
- [Extensible Structures](#extensible-structures)
- [Integrations](#integrations)
- [Extensions](#extensions)
- [AI](#ai)
- [CLI](#cli)
- [Emails](#emails)
- [Web Layer](#web-layer)

---

The backend is a Python Flask app built using our [Frasco framework](https://github.com/digicoop/frasco). It requires Python 3.10 and uses Poetry for dependency management.

The backend source is located in `src/kantree`.

## Architecture Overview

The main parts are:

 - SQLAlchemy models that provide query/schema for data (`kantree.data.models`)
 - action functions that contains the business logic (`kantree.actions`)
 - security function to validate access to data (`kantree.security`)
 - the kantree query language, KQL (`kantree.kql`)
 - the api layer that expose action functions and model queries (`kantree.api`)
 - the web pages served by the backend (`kantree.web`)

The backend is highly extensible:
 
 - blinker signals are triggered by actions: some signals can be hooked by integrations and automations
 - extensible elements are properly defined (`kantree.structures`)
 - built-in elements are cleanly defined (`kantree.builtins`):
    - attribute types are defined in `kantree.builtins.attr_types`

Communication with the frontend:

 - through the REST api
 - via push events through websockets (provided by `frasco.push`): internal signals can be exposed to the frontend (see `kantree.signals`)

## Code style guidelines

- Use **ruff** for linting and formatting
- Follow PEP 8 conventions
- Import order: standard library → third-party → local imports
- Use type hints where possible

## Testing

- Use **pytest** with fixtures in `tests/helpers/`
- Test files: `test_*.py`, test functions: `test_*`
- Backend tests: use API calls via `auth_client` helper
- Use existing `create_*` helpers for consistent test data

## Application Bootstrap

The application is created in `kantree.app`. The `create_app()` function initializes the Flask app with all Frasco extensions (Redis, Babel, Tasks, Users, Upload, Mail, Push, Billing) and Kantree modules.

Configuration is loaded by `load_config()` from multiple sources: default config in `kantree.config`, built-in definitions in `kantree/builtins/*.yml`, instance config in `config.yml`, and environment variables prefixed with `KANTREE_`.

Extensions are loaded from the `EXTENSIONS` config key. See `kantree.extensions.EXTENSION_ALIASES` for legacy path mappings.

## Data Layer

The data layer in `kantree.data` provides models, scopes, and serialization utilities.

### Models

SQLAlchemy models are in `kantree.data.models`, organized by domain (org, project, card, group, attribute, view, role, user, etc.). Each file groups related models.

### Scopes (`kantree.data.scope`)

Scopes provide contextual query filtering. They encapsulate filters for different contexts (project, card, org, team, portfolio, user) and are used by KQL and computed attributes to resolve queries.

### Serializer (`kantree.data.serializer`)

`KantreeDBSerializer` handles project import/export with ID remapping, used for duplication, templates, and backup/restore.

### Other utilities

`kantree.data.resolver` resolves references (by ID or name) to model instances. `kantree.data.marshallers` defines JSON serialization for the API.

## Actions

Actions in `kantree.actions` contain the business logic, organized by domain. They are the **only place** where business rules should be implemented.

The folder structure mirrors the domain model: `orgs`, `teams`, `users`, `projects`, `cards`, `card_groups`, `views`, `automations`, `integrations`, `webhooks`, etc.

Actions emit signals that trigger automations, webhooks, and real-time updates. See `kantree.actions.cards.signals` for card-related signals.

## Permissions System

The permissions system in `kantree.security` is structured in 3 levels: Organization → Team → Project.

### Organization level (`kantree.data.models.org.member`)

`OrganizationMember.permission` defines access at org level:

| Level | Constant | Description |
|-------|----------|-------------|
| 0 | `GUEST` | Must be explicitly added to each workspace |
| 1 | `MEMBER` | Can join and collaborate on workspaces |
| 2 | `MEMBER_CREATE_ITEM` | Member who can create workspaces |
| 3 | `ADMIN` | Can manage users and access all workspaces |
| 4 | `OWNER` | Can manage billing and org details |

Helper methods: `OrganizationMember.is_guest()`, `can_create_item()`, `is_admin()`, `is_owner()`

### Team level (`kantree.data.models.org.team`)

`TeamMember.permission` defines access within a team:

| Level | Constant | Description |
|-------|----------|-------------|
| 1 | `MEMBER` | Can collaborate on team workspaces |
| 2 | `MANAGER` | Can manage team workspaces |
| 3 | `ADMIN` | Can manage users and access all team workspaces |

### Project level (`kantree.data.models.role`)

Fine-grained permissions using `Role` and `RolePerm`:

- `Role`: belongs to an organization, contains a list of `RolePerm`
- `RolePerm`: `{object_type, actions[], project_id?, object_id?}`
- `ProjectMember.role`: links a user to a role in a project

The `object_id` field enables per-object permissions (e.g., restrict editing to specific groups).

### Object types and available actions

Each model class defines its permissions via `__permission_object_type__` and `__available_permission_actions__` attributes. See model files in `kantree.data.models` for the complete list (e.g., `Card`, `CardGroup`, `Project`, `CardComment`, etc.).

### Permission resolution (`kantree.security.perms`)

```python
# Check if action is allowed
is_allowed_in_project(project, target=card, actions=['EDIT'])

# Raise ApiNotAuthorizedError if not allowed
check_project_perms_or_403(project, target=card, actions=['EDIT'])

# Organization-level checks
check_org_perms_or_403(org, admin_required=True)

# Team-level checks  
check_team_perms_or_403(team, create_required=True)
```

`project.get_user_perms(user)` returns the computed permissions list for a user, taking into account:
- Direct project membership and role
- Org admin status (always admin on all projects)
- Team admin status (admin on team projects)
- Observer settings and public access

## KQL (Kantree Query Language)

KQL in `kantree.kql` is a domain-specific language for querying and computing values on cards.

**Filters** are boolean expressions to select cards. **Formulas** compute aggregate values. The parser (`kantree.kql.parser`) produces an AST that is converted to SQLAlchemy queries (`kantree.kql.filter`) or evaluated directly (`kantree.kql.query`).

KQL entities in `kantree.builtins.kql_entities` define queryable properties (card, group, project, user). Scopes from `kantree.data.scope` provide the query context.

## API Layer

The REST API is defined in `kantree.api.v1_0`. Each domain has its own module mirroring the actions structure.

Endpoints use Frasco's API decorators for routing, validation, and marshalling. Common utilities are in `kantree.api.pagination`, `kantree.api.validators`, and `kantree.api.utils`.

## Signals & Events

Signals in `kantree.signals` enable loose coupling between components. They are the foundation for automations, webhooks, integrations, and real-time updates.

**Signal types:**
- **Exposed signals** are broadcast to the frontend via WebSocket (Push)
- **Hookable signals** can trigger automations and integrations
- **Tracked signals** are logged for analytics

Card signals are defined in `kantree.actions.cards.signals`. `kantree.listeners` is the central place where signals are connected to handlers (automation execution, webhook delivery, cache invalidation, computed attribute recalculation).

Key utilities: `expose_signal()`, `signal_as_hook()`, `hookable_signal()`, `connect_to_hookable_signals()`.

## Extensible Structures

`kantree.structures` defines extensible structures with registries and base classes. Each structure type follows the same pattern: a registry dict, a base class, and a `register_*` decorator.

### Attribute Types

`kantree.structures.attr_type` defines `AttributeType` base class and `ATTRIBUTE_TYPES` registry. Built-in types are in `kantree.builtins.attr_types`.

### Automations

`kantree.structures.automation` defines three registries: `AUTOMATION_EVENTS` (triggers), `AUTOMATION_ACTIONS` (operations), and `AUTOMATION_QUERIES` (data accessors). Built-ins are in `kantree.builtins.automations`.

### Other structures

View modes (`kantree.structures.view_mode`), charts (`kantree.structures.chart`), exporters (`kantree.structures.exporter`), importers (`kantree.structures.project_importer`), and feature flags (`kantree.structures.feature_flags`) follow the same pattern. Built-ins are in the corresponding `kantree.builtins.*` folders.

## Integrations

Third-party integrations in `kantree.integrations` are Frasco extensions. Each integration extends `IntegrationBase` from `kantree.structures.integration` and can define hook handlers (`on_<signal_name>` methods) that are called asynchronously on signals.

See the `kantree.integrations` folder for implementation details and available integrations.

## Extensions

Extensions in `kantree.extensions` provide optional features enabled via configuration.

Authentication extensions (`kantree.extensions.auth`) provide LDAP and SAML SSO. Email inbound extensions handle incoming emails. Other extensions include `emailing` (transactional emails), `global_webhooks`, `pgsql_adapter`, and `saas` features.

## AI

AI features in `kantree.ai` provide LLM-based interactions. `kantree.ai.client` handles initialization, `kantree.ai.assistant` implements the conversational assistant, and `kantree.ai.tools` defines available function calls.

## CLI

The CLI in `kantree.cli` provides administrative commands. Run with `scripts/kantree <command>`. Main modules: `admin` (user/org management), `export` (data export), `fixes` (database fixes).

## Emails

Email templates in `kantree/emails/` use Markdown and HTML with Jinja2. Translations are in the `fr/` subfolder. `kantree.extensions.emailing` handles rendering and delivery via `frasco.mail`.

## Web Layer

`kantree.web` serves HTML pages and manages frontend assets. Key modules: `assets` (esbuild integration), `js_api` (JavaScript API generation), `security` (CSRF, CSP), `oauth` (OAuth routes). Templates are in `kantree.web.templates`.
