Skip to content

Shared Concepts

This section explains concepts that cut across multiple apps .

These are not owned by a single app, but are consistently reused patterns that define how the system behaves.

If you understand this section, you will:

  • stop duplicating logic
  • know where to extend vs where to reuse
  • avoid breaking invisible contracts between apps

Role-Based Architecture (Customer vs Seller)

Core Idea

There are no separate user tables for customers and sellers.

Instead:

  • One User model
  • Role flags define behavior
User
 ├── is_customer
 ├── is_seller
 └── is_staff

Why This Matters

  • A seller can also be a customer
  • Same login, same identity
  • Shared history (orders, products, support)

Where This Is Used

  • auth_email.LoginView → role-based redirects
  • seller.mixins.IsSellerMixin
  • customer.mixins.IsCustomerMixin
  • Shared generic views in users

Customization Guidance

Safe:

  • Add new roles (e.g. is_affiliate)
  • Add role-based panels

Dangerous:

  • Splitting User into multiple tables
  • Hardcoding role logic inside business apps

Generic Views as a Reuse Contract

Concept

The users app defines generic, role-agnostic base views .

Examples:

  • GenericUserProfileView
  • GenericPasswordChangeView
  • GenericOrderHistoryView
  • GenericMyProductListView
  • GenericMySupportListView

These views:

  • contain business-safe logic
  • accept presentation config via subclassing

How It Works

users.GenericMyProductListView
customer.CustomerMyProductListView
seller.SellerMyProductListView

Each subclass only provides:

  • base_template
  • active_page
  • optional form class

Why This Is Important

  • No duplicated logic
  • Bug fixes apply everywhere
  • Behavior remains consistent

Customization Guidance

Safe:

  • Add new generic views
  • Extend templates

Dangerous:

  • Using generic views directly in urls.py
  • Changing base logic without checking all consumers

PurchasedProduct as an Access Token

Concept

PurchasedProduct is not just a table.

It is a permission artifact .

It answers exactly one question:

“Does this user own this product?”

System-Wide Usage

Used by:

  • Downloads (payments)
  • Product listing (users)
  • Support eligibility (depsupport)
  • Seller analytics (seller)
  • Admin visibility (users/admin.py)

Key Rule

If PurchasedProduct does not exist, access does not exist.

This rule is never bypassed.

Customization Guidance

Safe:

  • Add metadata to PurchasedProduct
  • Add expiry logic (subscriptions)

Dangerous:

  • Granting access without creating PurchasedProduct
  • Checking ownership via orders directly

Order Lifecycle vs Access Lifecycle

Important Distinction

Concept Meaning
Order Payment attempt
PurchasedProduct Access grant

Orders can be:

  • pending
  • failed
  • refunded

PurchasedProduct exists only when:

  • payment is successful
  • access should be granted

Why This Separation Exists

  • Refunds revoke access cleanly
  • Failed payments do not pollute access
  • Admin actions remain reversible

Where This Pattern Appears

  • payments_dodo.webhook
  • payments.admin
  • Download views

Signals as Side-Effect Boundaries

Concept

Signals are used only for side effects , never for business decisions.

Examples:

  • Create Dodo customer on user creation
  • Sync product with payment provider
  • Auto-generate slugs

What Signals Must NOT Do

  • Decide access
  • Change order state
  • Trigger irreversible workflows

Why This Rule Exists

Signals:

  • are implicit
  • are hard to debug
  • can fire multiple times

They are intentionally limited.


Background Tasks (Celery) as Reliability Layer

What Celery Is Used For

  • Emails
  • Telegram notifications
  • Database backups

What Celery Is NOT Used For

  • Granting access
  • Payment confirmation
  • Core state transitions

Design Principle

Business state changes must be synchronous and atomic.

Side effects can be async.

This prevents:

  • partial purchases
  • ghost access
  • race conditions

Middleware as Global Authority

Concept

Some rules must override all apps .

Example:

  • Under construction mode

Why Middleware

  • Runs before views
  • Cannot be bypassed accidentally
  • Enforced globally

Rule

Only system-level concerns belong in middleware.


Cache as a Performance Optimization, Not Truth

Cache Usage

  • Short URLs
  • Under construction state
  • Analytics data

Rule

Cache may lie. Database must not.

All cached data:

  • has TTL
  • is safe to invalidate
  • has DB fallback

Environment Awareness (Dev vs Prod)

Shared Pattern

Many components behave differently based on environment:

Feature Dev Prod
File download Local FS Signed S3 URL
Storage Local DO Spaces
DB Backup Local FS Cloud
Debug On Off

Why This Matters

  • Local development stays simple
  • Production stays secure
  • Same codebase, different behavior

Why Shared Concepts Matter More Than Apps

Apps can be replaced.

Shared concepts cannot .

If you customize:

  • follow the shared rules
  • reuse the patterns
  • don’t fight the architecture