Skip to content

Core Architecture

The core app defines the foundational architecture of the backend.

It is responsible for how requests are processed, how permissions are enforced, and how business actions are tracked across the system.


Overview

The backend follows a layered, service-first architecture:

Request → Middleware → Request Context → Permissions → Views → Services → Audit → Response

Each layer has a clear responsibility and avoids leaking concerns into other layers.


flowchart LR
    A[Client Request] --> B[Middleware]
    B --> C[Request Context Resolution]
    C --> D[DRF Permissions]
    D --> E[View Layer]
    E --> F[Service Layer]
    F --> G[Policy Layer]
    F --> H[Audit Logging]
    F --> I[Database]

    G --> F
    H --> I

    F --> J[Response]
    J --> K[Client]

Request Lifecycle

1. Incoming Request

A request enters the system with headers such as:

  • X-ORG-SLUG
  • X-ORG-ID
  • X-CUSTOMER-ORG-ID

These headers define the tenant (organization) context.


2. Middleware

The CurrentOrgMiddleware runs early in the request lifecycle.

Its responsibility is minimal:

  • initialize request.org and request.customer_org
  • delegate resolution to the request context service

It does not perform complex logic itself.


3. Request Context Resolution

Handled in core.services.request_context.

This step:

  • resolves the active organization
  • validates membership
  • supports superuser overrides
  • attaches:
  • request.org
  • request.organization
  • request.customer_org

If resolution fails: - the request continues - permissions will later reject access


4. Permission Layer

DRF permissions (in core.policies.permissions) enforce access:

Examples: - HasCurrentOrg - HasCurrentCustomerOrg - IsInternalUser - IsCustomerUser

Responsibilities:

  • ensure authentication
  • ensure valid org context
  • attach org if not already resolved

This layer bridges HTTP requests to domain logic.


5. Views (Thin Layer)

Views are intentionally minimal.

They: - validate input (serializers) - call service functions - translate exceptions into HTTP responses

They do NOT: - contain business logic - perform authorization checks directly


6. Service Layer (Source of Truth)

All business logic lives in services.

Examples: - org membership management - team management - team membership lifecycle

Services: - enforce rules - call policies for authorization - write audit logs - ensure data consistency

This is the most important layer in the system.


7. Policy Layer (Authorization Logic)

Policies live in core.policies.

They define reusable permission logic such as:

  • can_manage_org_members
  • can_manage_teams
  • can_view_team
  • can_manage_team_memberships

Policies replace:

  • scattered role checks
  • duplicated permission logic

They enable:

  • consistency
  • testability
  • future extensibility (RBAC / ABAC)

8. Audit Logging

All important state changes are logged via:

log_audit(...)

Audit logs include: - actor (who performed the action) - action (what happened) - object (what was affected) - changes (structured diff) - metadata (IP, user agent)

Audit logging is triggered inside services.


9. Response

The response is returned through DRF.

Errors are normalized via:

core.exceptions.api_exception_handler

This ensures a consistent response format across the API.


Key Architectural Principles

1. Separation of Concerns

Each layer has a single responsibility:

  • middleware → request setup
  • permissions → access control
  • views → orchestration
  • services → business logic
  • policies → authorization rules
  • audit → traceability

2. Service-First Design

All business logic must live in services.

This ensures: - reuse across endpoints - consistent behavior - easier testing


3. Policy-Based Authorization

Authorization is:

  • centralized
  • reusable
  • independent from views

Avoid: - inline role checks - duplicated permission logic


4. Explicit Context

The system never relies on implicit global state.

All context comes from:

  • request headers
  • resolved request attributes

This ensures: - clarity - debuggability - multi-tenant safety


5. Strong Auditability

All critical actions must be traceable.

Audit logs are: - structured - consistent - queryable

This supports: - debugging - compliance - analytics


Data Flow Example

Example: Updating a team

  1. Request arrives with X-ORG-SLUG
  2. Middleware initializes request
  3. Request context resolves org
  4. Permission checks user access
  5. View validates payload
  6. Service updates team
  7. Policy validates permissions
  8. Audit log is created
  9. Response is returned

Anti-Patterns to Avoid

Do NOT:

  • put business logic in views
  • bypass service layer
  • duplicate permission checks
  • access request.org outside controlled flow
  • skip audit logging for critical actions

Summary

The core architecture ensures:

  • consistent behavior across all apps
  • secure multi-tenant isolation
  • centralized authorization
  • full audit traceability

It is designed to scale with increasing complexity while remaining maintainable and predictable.