Skip to content

Approvals

Purpose

The approvals app provides a generic, extensible approval workflow system.

It enables:

  • requesting approvals for arbitrary objects (via generic relations)
  • assigning approvers (direct + delegated)
  • managing approval decisions (approve / reject)
  • forwarding approvals between users
  • tracking delegation of approval responsibility

It acts as the central decision engine for business workflows such as:

  • timesheet submissions
  • (future) expense approvals
  • (future) PTO requests
  • (future) inventory or operational approvals

Key concepts

Approval

A single approval request tied to a target object.

  • generic relation (content_type, object_id)
  • has a lifecycle (pending → approved/rejected)
  • stores decision metadata and payload

ApprovalAssignee

Represents who can act on an approval.

  • direct assignment (e.g. manager)
  • forwarded assignment
  • computed via services

ApprovalDelegation

Allows one user to delegate approval responsibility to another.

  • time-bound (starts_at, ends_at)
  • kind-aware (global or per approval type)
  • used in:
  • inbox visibility
  • permission checks
  • decision authority

ApprovalKind

Defines what type of approval flow is being executed.

Examples:

  • timesheet_submit

Used to:

  • drive assignee computation
  • scope delegations
  • apply side effects

Inbox

A filtered view of approvals visible to a user.

Includes:

  • direct assignments
  • delegated approvals
  • forwarded approvals

Decision workflow

The process of:

  • validating permissions
  • applying approval decision
  • triggering side effects
  • notifying relevant users

Entry points

API endpoints

Defined in views.py:

  • GET /approvals/
  • GET /approvals/inbox/
  • GET /approvals/{id}/
  • POST /approvals/{id}/decide/
  • POST /approvals/{id}/forward/
  • POST /approvals/{id}/unforward/

Delegations:

  • GET /approval-delegations/
  • GET /approval-delegations/me/
  • POST /approval-delegations/
  • POST /approval-delegations/{id}/disable/
  • DELETE /approval-delegations/{id}/

Admin

  • Django admin for:
  • Approval
  • ApprovalDelegation
  • ApprovalAssignee

Tasks

Currently:

  • no dedicated Celery tasks

Future potential:

  • approval reminders
  • escalation workflows
  • SLA enforcement

Signals

Currently:

  • no Django signals used

Side effects are handled explicitly in:

  • handlers.py

Dependencies

Depends on

  • orgs
  • org scoping
  • membership and roles
  • teams
  • manager resolution (effective_manager)
  • timesheets
  • approval targets
  • side effects
  • notifications
  • user notifications
  • core
  • audit logging
  • Django:
  • ContentType (generic relations)

Used by

  • timesheets
  • triggers approval creation
  • consumes approval decisions

Future:

  • any app needing approval workflows

Operational notes

Known pitfalls

  • Generic relations
  • no DB-level FK enforcement → validate carefully
  • Duplicate approvals
  • guarded by unique constraint, but still needs care in services
  • Delegation complexity
  • time + kind + assignment interactions can be subtle
  • Forwarding vs assignment
  • forwarding overrides visibility rules
  • Payload growth
  • audit and forwarding history stored in JSON field

Performance considerations

  • Inbox queries use:
  • Exists subqueries
  • annotations
  • Prefetching is critical:
  • assignees
  • related users
  • Serializer context avoids N+1 queries:
  • timesheet meta map
  • delegation info map
  • Bulk operations used for:
  • assignee refresh

Design characteristics

The approvals system is:

  • generic → works for any model
  • org-scoped → multi-tenant safe
  • delegation-aware → supports real-world org structures
  • extensible → new approval kinds easily added
  • service-driven → business logic centralized outside views

Summary

The approvals app provides a flexible and extensible approval workflow engine.

It supports:

  • assignment-based approvals
  • delegation-aware decision making
  • forwarding workflows
  • side-effect handling
  • notification integration

This makes it a core building block for controlled, auditable decision flows across the system.