Package map
A navigation map of the Django apps in apps/ — what each is for, and which way
dependencies flow. Use it to find where a concern lives and to gauge the blast radius
of a change before making it.
This is a role map, not a strict layering. The import graph is a connected graph, not an acyclic stack of layers: foundational apps are imported almost everywhere, and a few apps import very widely. The direction below describes the dominant flow, not an invariant the code never crosses — that is why there is no import-linter contract enforcing it (see the note at the end).
Dependency direction
Dependencies flow downward: entry points depend on domain apps, which depend on the foundation. The foundation depends on nothing above it.
flowchart TD
EP["Entry points<br/>api · web · admin · dashboard · prelogin · users · oauth · sso"]
DOM["Domain & runtime<br/>experiments · chatbots · pipelines · assistants · custom_actions · service_providers<br/>chat · channels · participants · slack · documents · files"]
FEAT["Evaluation, analytics & support<br/>evaluations · human_annotations · annotations · assessments<br/>trace · events · cost_tracking · usage_metrics · analysis · ocs_notifications · banners · help · filters · mcp_integrations"]
FND["Foundation<br/>teams · utils · generics · web · audit · data_migrations"]
EP --> DOM
EP --> FEAT
DOM --> FEAT
FEAT --> DOM
DOM --> FND
FEAT --> FND
EP --> FND
Tiers
Foundation
Cross-cutting infrastructure imported almost everywhere. Changes here have the widest blast radius.
| App | Responsibility |
|---|---|
teams |
Multi-tenancy root — BaseTeamModel, team middleware, auth decorators/mixins. See multi-tenancy guide. |
utils |
Shared base models (BaseModel), custom fields, factories, helpers. |
generics |
CRUD view/table scaffolding (make_crud_urls, generic actions). |
web |
Base views, shared page chrome, health checks. |
audit |
Field-level audit logging. |
data_migrations |
Long-running/managed data migrations. |
Domain & runtime
The chatbot model and the machinery that runs conversations.
| App | Responsibility |
|---|---|
experiments |
The Experiment (a.k.a. Chatbot) model, versioning, sessions. Imported by 27 apps. |
chatbots |
Chatbot-facing UI layer over experiments. |
pipelines |
DAG workflow definition and runtime (LLM/router/custom-action nodes). |
assistants |
OpenAI Assistants integration. |
custom_actions |
HTTP API wrappers (OpenAPI schema) callable from pipelines. |
service_providers |
Credentials + LlmService/MessagingService abstractions for LLM, messaging, voice, tracing. |
chat |
Chat/message models and history. |
channels |
Platform integration + webhook routing (Telegram, WhatsApp, Slack, API, web, email, Connect). |
participants |
Participant identity across channels. |
slack |
Slack platform app (events, install/OAuth). |
documents |
Document/collection management for retrieval. |
files |
File storage and access. |
Evaluation, analytics & support
Features layered on top of the domain, plus supporting services.
| App | Responsibility |
|---|---|
evaluations |
Evaluation configs, runs, and datasets. |
human_annotations |
Reviewer annotation queues and consensus. See ADR-0015. |
annotations |
Tags and comments attached to domain objects (imported widely). |
assessments |
Lean Score value layer. See ADR-0012. |
trace |
Trace/Span observability records for requests and pipeline steps. |
events |
Event triggers and scheduled actions. |
cost_tracking |
LLM usage and cost accounting. |
usage_metrics |
Shared activity-metric read path (sessions, messages, participants) for the dashboard and usage API. Definitions in ADR-0051. Models-free. |
analysis |
Analysis pipelines over conversation data. |
ocs_notifications |
In-app notifications. |
banners |
Site banners. |
help |
In-app help / help agents. |
filters |
Reusable list-filter definitions. |
mcp_integrations |
Model Context Protocol integrations. |
Entry points
Top of the stack — nothing imports these; they wire the domain to the outside world.
| App | Responsibility |
|---|---|
api |
DRF REST API (/api/) + OpenAI-compatible endpoints. See API versioning ADRs. |
web |
Server-rendered web UI (also foundational for shared chrome). |
admin |
Staff-only admin area. |
dashboard |
Analytics dashboard. |
prelogin |
Public marketing pages. |
users · oauth · sso |
Authentication and account management. |
Blast radius
These apps are dependency magnets — a large fraction of the codebase imports them, so changes ripple widely. Treat their public surfaces as contracts and lean on the guard tests when touching them:
| App | Imported by (# apps) | Guarded by |
|---|---|---|
teams |
~35 | apps/teams/tests/test_multitenancy_guards.py, test_view_auth_guard.py |
utils |
~29 | — |
experiments |
~27 | model versioning tests |
service_providers |
~23 | — |
chat, web, channels, annotations, generics |
~17–18 | — |
Why no import-linter contract
An import-linter layering contract was considered but rejected: the tool's current
release forces a downgrade of a runtime dependency (typer, pulled in by taskbadger
and transformers) to resolve, which is not worth it for a dev-only check. The import
graph is also genuinely cyclic between the domain and feature tiers, so a strict
layering contract would not hold without extensive ignore_imports exceptions. The
existing scripts/check_inline_imports.py
guard already covers the one import rule that is mechanically enforced (no unjustified
function-level imports).