Learn from OSS
Plane

Plane Architecture Overview

Plane's three-tier architecture — database, API, frontend, state management, and real-time services

Plane Architecture Overview

For Product Managers

This page explains how Plane is structured as a software system. You don't need to understand every technical detail — focus on the diagrams and the "Why It Matters" callouts to build a mental model of how the product works under the hood.

Plane uses a three-tier architecture with React applications for the UI, a Django and DRF backend for business logic, PostgreSQL and supporting services for persistence, and Hocuspocus plus Celery for collaboration and background work. This page breaks down how those layers fit together and why that structure supports self-hosting, real-time editing, and product complexity.

How Plane's Architecture Works

Plane follows a three-tier architecture with a real-time collaboration layer, served through a Caddy reverse proxy:

┌─────────────────────────────────────────────────────────────────┐
│                         USERS (Browser)                         │
└──────────────────────────────┬──────────────────────────────────┘

                    ┌──────────▼──────────┐
                    │  Caddy Proxy (2.10)  │  ← automatic HTTPS
                    │  Port 80 / 443       │    routes by path
                    └──┬──────┬───────┬───┘
                       │      │       │
       ┌───────────────▼─┐ ┌──▼─────┐ ┌▼───────────────┐
       │  Web / Admin /   │ │  API   │ │  Live Server    │
       │  Space (React)   │ │(Django │ │ (Hocuspocus)    │
       │  Nginx           │ │ DRF)   │ │ WebSocket CRDT  │
       │  :3000/3001/3002 │ │ :8000  │ │ :3100           │
       └──────────────────┘ └──┬─────┘ └─────────────────┘

              ┌────────────────┼────────────────┐
              │                │                │
       ┌──────▼──────┐ ┌──────▼──────┐ ┌───────▼───────┐
       │ PostgreSQL   │ │   Valkey    │ │  MinIO / S3   │
       │   15.7       │ │   7.2.11    │ │ (File Storage)│
       │ (Primary DB) │ │ (Cache)     │ │               │
       └──────────────┘ └─────────────┘ └───────────────┘

                        ┌──────▼──────┐
                        │  RabbitMQ   │
                        │   3.13.6    │
                        │ (MQ Broker) │
                        └──────┬──────┘

                        ┌──────▼──────┐
                        │   Celery    │
                        │  Workers    │
                        │  + Beat     │
                        └─────────────┘

Why It Matters

Every user request flows through Caddy → the appropriate service. REST API calls hit Django; real-time editing uses WebSockets to the Hocuspocus live server. Background work (email notifications, cleanup, imports) runs through Celery workers using RabbitMQ as the message broker. Valkey (Redis-compatible) handles caching and sessions. This separation means the API stays fast even when heavy async work is running.

The Three Tiers

1. Frontend Layer (React 18 + MobX)

The frontend is built with React 18, React Router 7 (with SSR support), and MobX for state management. Three separate apps share packages:

AppPortPurpose
web3000Main user-facing application (issues, boards, pages)
admin3001Instance administration (/god-mode/)
space3002Public-facing project views (shareable links)

MobX Store Hierarchy (180+ files):

RootStore
  ├── router.store           → routing state
  ├── theme.store             → UI theme
  ├── instance.store          → instance config
  ├── user/
  │     ├── profile.store     → current user
  │     ├── account.store     → auth account
  │     └── settings.store    → user preferences
  ├── workspace/
  │     ├── index.ts          → workspace data
  │     ├── home.ts           → home dashboard
  │     ├── webhook.store     → webhook management
  │     └── api-token.store   → API tokens
  ├── project/
  │     ├── project.store     → project CRUD
  │     └── project_filter    → view filters
  ├── issue/                  → issue stores per context
  │     ├── project/          → project issue list
  │     ├── cycle/            → cycle issues
  │     ├── module/           → module issues
  │     └── workspace-draft/  → draft issues
  ├── pages/                  → wiki pages
  ├── notifications/          → notification center
  ├── timeline/               → activity timeline
  └── ...

Why MobX + SWR?

MobX provides fine-grained reactivity: when a single issue's title changes, only the components rendering that title re-render. SWR complements MobX by handling data fetching and cache invalidation. MobX stores hold the canonical state; SWR fetches and revalidates from the API.

2. API Layer (Django 4.2 + DRF)

The backend is Django 4.2.29 LTS with Django REST Framework 3.15.2, living at apps/api/.

URL Routing Structure:

/api/             → plane.app.urls       (main app — workspaces, projects, issues)
/api/public/      → plane.space.urls     (public/anonymous endpoints)
/api/instances/   → plane.license.urls   (instance management)
/api/v1/          → plane.api.urls       (API key–based access)
/auth/            → plane.authentication (login, OAuth, magic links)

App-level URL modules (20+):

plane/app/urls/
  ├── analytic.py, api.py, asset.py, cycle.py, estimate.py
  ├── external.py, intake.py, issue.py, module.py, notification.py
  ├── page.py, project.py, search.py, state.py, user.py
  ├── views.py, webhook.py, workspace.py, timezone.py, exporter.py

Key API Patterns:

PatternDescription
Hierarchical URLsWorkspaces → Projects → Issues/Cycles/Modules
Standard RESTGET, POST, PATCH, DELETE
Throttling30/min anon, 60/min API key, custom per-endpoint
Serializer validationDRF serializers validate all input/output
API documentationdrf-spectacular (OpenAPI/Swagger)

3. Database Layer (PostgreSQL 15.7)

PostgreSQL with 30+ model files and 126 migrations.

Core Entity-Relationship Map:

                         ┌──────────────┐
                         │   Workspace  │ ← multi-tenancy root
                         └──────┬───────┘
                                │ has many
                    ┌───────────┼───────────┐
                    │           │           │
             ┌──────▼──────┐   │    ┌──────▼──────┐
             │   Project    │   │    │   Member    │
             └──────┬───────┘   │    └─────────────┘
                    │           │
         ┌──────────┼──────┬───┼──────┐
         │          │      │   │      │
   ┌─────▼────┐ ┌──▼───┐ ┌▼───▼─┐ ┌──▼─────┐
   │  Issue    │ │Cycle │ │Module│ │ State  │
   │ (central)│ │      │ │      │ │        │
   └────┬─────┘ └──┬───┘ └──┬───┘ └────────┘
        │          │        │
        │    CycleIssue  ModuleIssue
        │      (M2M)       (M2M)

   ┌────┼────┬──────────┬─────────┐
   │    │    │          │         │
 Comment Activity  Reaction  Attachment

Base Model Pattern — all workspace models inherit:

FieldPurpose
idUUID primary key
created_atAuto-set on creation
updated_atAuto-set on every save
created_byForeign key to User
updated_byForeign key to User
deleted_atSoft-delete timestamp (null = active)
workspaceForeign key enforcing multi-tenancy

Key Design Patterns

Multi-Tenancy

Every query is scoped to a workspace — enforced at the view level so no data leaks between organizations.

Soft Deletion

Records are never physically deleted. deleted_at is set, and a daily Celery beat task permanently removes records older than HARD_DELETE_AFTER_DAYS.

Activity Audit Trail

Every change to an Issue generates an IssueActivity record tracking what changed, who changed it, and when.

Community / Enterprise Gating

The web app has ce/ (community edition) and ee/ (enterprise edition) directories, enabling feature gating between the free and paid versions.

Real-Time Collaboration

The Live server (apps/live/) runs Hocuspocus on port 3100:

ComponentTechnology
ServerHocuspocus 2.15.2 (Node.js)
CRDTYjs 13.6.20
Editor bindingy-prosemirror (Yjs ↔ ProseMirror)
Persistence@hocuspocus/extension-database + Redis
TransportWebSocket via express-ws

When users edit Pages collaboratively, the Hocuspocus server merges their changes using CRDT math, persists to the database, and broadcasts updates to all connected clients.

Performance Architecture

Database

  • Indexes on frequently queried fields (workspace_id, project_id, state_id)
  • Read replica support for horizontal scaling

API

  • Valkey caching for frequently accessed data
  • Throttling at multiple levels (anon, API key, asset, email verification)
  • GZip middleware for response compression

Frontend

  • MobX computed values — derived state only recalculates when dependencies change
  • Code splitting — lazy-loaded routes via React Router
  • SWR caching — stale-while-revalidate pattern for API data

What's Next