--- since: 1.2.1 --- # DjangoPlay — Architecture Style --- # 1. Overview DjangoPlay is structured as a **modular monolith** built on Django and Django REST Framework. The application combines: - Domain-oriented Django apps - Layered application architecture - Service-oriented business logic - Centralized authorization - External identity through AuthX - Auditability - Asynchronous processing with Celery - Redis-backed infrastructure - Dedicated integration boundaries - Versioned REST APIs The architecture is intentionally modular without introducing microservices prematurely. The primary goal is to keep domain functionality isolated and maintainable while allowing infrastructure, integrations, and individual application modules to evolve independently. --- # 2. Architecture Classification | Category | Architecture Style | |---|---| | System Architecture | Modular Monolith | | Application Architecture | Layered Architecture | | Domain Structure | Domain-Oriented Django Apps | | Business Logic | Service Layer | | Data Access | Django ORM / Query Services | | Authorization | Policy-Based Access Control | | Identity | External AuthX Identity Service | | API | Django REST Framework | | API Evolution | URL-Based API Versioning | | Background Processing | Celery | | Broker / Cache | Redis | | Persistence | PostgreSQL | | External Services | Dedicated Integration Boundaries | | Auditability | Centralized Audit Module | | Deployment | Nginx + Gunicorn + Celery | | Static Assets | Local Static Serving / Cloudflare R2 + CDN | | Issue Tracking | Generic Issue Tracker Integration | --- # 3. Modular Monolith DjangoPlay uses a **modular monolith** rather than a collection of independent microservices. Multiple domain modules run inside the same Django application and share the application's deployment and primary PostgreSQL database. The current application contains domain and infrastructure modules such as: ```text webapp/ ├── aicore ├── apidocs ├── audit ├── core ├── entities ├── finance ├── frontend ├── helpdesk ├── industries ├── locations ├── mailer ├── paystream ├── policyengine ├── teamcentral ├── users │ └── integrations/ └── issuetracker/ ```` The exact set of applications may evolve as DjangoPlay develops. The important architectural rule is that each application represents a meaningful responsibility or domain rather than being an arbitrary collection of unrelated functionality. --- # 4. Domain-Oriented Application Structure Each Django application owns a defined area of responsibility. Examples include: | Application | Responsibility | | -------------- | ------------------------------------------------------------- | | `users` | User accounts, authentication flows, signup and verification | | `teamcentral` | Teams, organizational structure and related access context | | `policyengine` | Role-based authorization and policy evaluation | | `audit` | Platform-wide audit trail | | `entities` | Business/entity records | | `locations` | Geographic reference data | | `industries` | Industry and classification reference data | | `finance` | Financial domain functionality | | `helpdesk` | Support workflows and issue/report handling | | `mailer` | Transactional email functionality | | `aicore` | In-app AI assistant and provider orchestration | | `apidocs` | API documentation and developer-facing API support | | `frontend` | Templates, static assets and presentation-layer functionality | | `core` | Cross-cutting application infrastructure | | `paystream` | Project package, settings, security and integration wiring | The application boundaries are logical boundaries inside the monolith. They are not necessarily separate deployable services. --- # 5. Layered Application Architecture DjangoPlay separates request handling, application workflows, domain state, and infrastructure concerns. ```text Incoming Request │ ▼ Middleware / Context │ ▼ URL Routing │ ┌────────────┴────────────┐ ▼ ▼ Django Web Views DRF APIs │ │ └────────────┬────────────┘ ▼ Service Layer │ ┌─────────────┼─────────────┐ ▼ ▼ ▼ Policies Models Tasks │ │ │ │ ▼ ▼ │ PostgreSQL Redis │ └─────────────┬─────────────┐ ▼ ▼ Audit Integrations ``` The architecture intentionally keeps core business workflows out of the presentation layer. --- # 6. Presentation Layer The presentation layer is responsible for interacting with clients. It includes: * Django web views * DRF API views and ViewSets * Templates * Serializers * Presentation-specific request/response handling The presentation layer should: * Receive requests * Validate request structure * Resolve the appropriate service * Return responses * Handle presentation-specific concerns It should **not become the primary location for business workflows**. Typical flow: ```text HTTP Request │ ▼ View / API View │ ▼ Serializer │ ▼ Service │ ▼ Response ``` --- # 7. Service Layer The service layer is the primary location for application and business workflows. Services coordinate: * Business rules * Transactions * Domain workflows * Model operations * Authorization checks * External integrations * Background task dispatch * Notifications * Audit operations Typical flow: ```text View / API │ ▼ Service │ ├── Policy ├── Model / Query ├── Audit ├── Celery Task └── Integration ``` Services provide a stable application boundary so that the same business operation can be reused by different entry points. For example, a workflow should not need to be duplicated because it is invoked from both a Django web view and an API endpoint. --- # 8. Domain and Data Layer Django models represent persistent domain state and relationships. The domain/data layer contains: * Django models * Relationships * Persistence-facing state * Model-level validation appropriate to the domain * Domain-specific state transitions where appropriate Complex application workflows should remain in services rather than becoming embedded inside model methods. Database access is primarily provided through the Django ORM. Where queries become complex or reusable, query/selector services can isolate that logic from views and workflows. --- # 9. Query and Selector Pattern Complex or reusable data retrieval should be isolated from presentation code. Typical responsibilities include: * Filtering * Search * Ordering * Related-object loading * Query optimization * Reusable domain queries Conceptually: ```text Service │ ▼ Query / Selector │ ▼ Django ORM │ ▼ PostgreSQL ``` This prevents large query expressions from becoming scattered throughout views and other application components. --- # 10. Authorization Architecture Authorization is treated as a cross-cutting concern rather than being implemented independently in every view. DjangoPlay uses the `policyengine` application for centralized authorization logic. Policies can evaluate application context such as: * User roles * Ownership * Organizational context * Allowed actions * Resource access * Role-based permissions Typical flow: ```text Request │ ▼ Authentication │ ▼ Policy Evaluation │ ├── Allowed ──► Application Service │ └── Denied ──► Access Denied ``` Authorization should be enforced at the appropriate application boundary rather than relying solely on presentation-layer checks. --- # 11. Identity Architecture DjangoPlay uses **AuthX as its external identity service**. Identity responsibilities are deliberately separated from DjangoPlay's domain/application responsibilities. AuthX provides the identity authority for authentication flows such as: * Login * Signup * Password reset * Identity verification * SSO The architectural boundary is: ```text ┌──────────────────┐ │ AuthX │ │ Identity Service │ └────────┬─────────┘ │ Identity / JWT │ ▼ ┌──────────────────┐ │ DjangoPlay │ │ Application │ └──────────────────┘ ``` AuthX is the JWT signing authority for the AuthX identity integration. DjangoPlay verifies AuthX-issued identity tokens rather than owning the AuthX private signing key. This separation protects the identity boundary and keeps authentication infrastructure independent from application-domain logic. --- # 12. Audit Architecture Auditability is a platform-level concern. The `audit` application provides centralized audit logging for meaningful system actions and state changes. Typical events include: * Authentication-related events * Administrative actions * Create operations * Update operations * Delete operations * State transitions * Important system operations Conceptually: ```text Application Service │ ▼ Audit Service │ ▼ Audit Log │ ▼ PostgreSQL ``` Audit operations should remain attributable to the actor or system process responsible for the change. --- # 13. Background Processing DjangoPlay uses **Celery** for asynchronous and long-running work. Redis provides the supporting broker/cache infrastructure. Typical flow: ```text Application Service │ ▼ Celery Task │ ▼ Redis │ ▼ Celery Worker │ ▼ External Service / Database / File Operation ``` Background processing is appropriate for operations such as: * Transactional email * External API calls * File processing * Long-running operations * Scheduled maintenance * Synchronization workflows The request/response path should not unnecessarily perform long-running work that belongs in the background processing layer. --- # 14. Integration Architecture External systems are accessed through explicit integration boundaries. The application should not scatter third-party API calls throughout domain views or models. Conceptually: ```text DjangoPlay Service │ ▼ Integration Boundary │ ▼ External Service ``` This architecture allows external providers to be replaced or modified without restructuring the application's core domain workflows. Current integration categories include: * AuthX Identity * Generic Issue Tracker * Email / SMTP providers * AI providers * Cloudflare R2 * Other external APIs --- # 15. Generic Issue Tracker Integration DjangoPlay integrates with the reusable **Generic Issue Tracker** package rather than maintaining an isolated issue-tracking implementation inside the host application. The integration is located under: ```text paystream/integrations/issuetracker/ ``` The reusable package provides issue-management capabilities while DjangoPlay provides the host-specific integration, access control, and application workflows. Conceptually: ```text DjangoPlay │ ▼ Helpdesk / Application Workflows │ ▼ DjangoPlay Issue Tracker Integration │ ▼ Generic Issue Tracker │ ├── Issues ├── Comments ├── Attachments ├── Labels └── Status History ``` This keeps the issue-tracking capability reusable while allowing DjangoPlay to apply its own application-level policies and workflows. The `helpdesk` application acts as an important host-side integration point for bug reports, support tickets, and issue-tracker workflows. --- # 16. Email Architecture Email delivery is isolated from individual business modules through the mailer infrastructure. Typical flow: ```text Application Service │ ▼ Mailer │ ▼ Celery Task │ ▼ SMTP / Provider ``` This prevents individual applications from implementing SMTP or provider communication independently. Email configuration and provider credentials are maintained separately from business-domain logic. --- # 17. AI Integration Architecture The `aicore` application provides the in-app AI assistant and acts as the application boundary for AI provider communication. The provider implementation is intentionally replaceable. Conceptually: ```text Authenticated User │ ▼ aicore │ ▼ Provider Registry │ ┌────┼───────────────┐ ▼ ▼ ▼ xAI OpenAI Custom Providers │ Ollama / vLLM / ... ``` AI provider credentials and provider-specific configuration remain outside domain application logic. The architecture supports changing providers without changing the rest of the application workflow. Detailed AI architecture belongs in the dedicated `aicore` documentation rather than this system architecture document. --- # 18. API Architecture DjangoPlay exposes REST APIs through Django REST Framework. API endpoints are organized using explicit URL namespaces. Typical structure: ```text /api/v1/ │ ├── users/ ├── issues/ ├── ... │ └── ... ``` API endpoints follow the same application architecture as web requests: ```text DRF View / ViewSet │ ▼ Serializer │ ▼ Service │ ▼ Domain / Integration ``` API presentation code should not duplicate business workflows that already exist in the service layer. --- # 19. API Versioning DjangoPlay uses URL-based API versioning to allow controlled API evolution. For example: ```text /api/v1/ /api/v2/ ``` A version may provide its own: * URL configuration * Views * Serializers * Version-specific presentation behavior The underlying business services can remain shared where the business semantics are unchanged. Conceptually: ```text Client │ ┌────────┴────────┐ ▼ ▼ /api/v1/ /api/v2/ │ │ v1 Views v2 Views │ │ v1 Serializers v2 Serializers │ │ └────────┬────────┘ ▼ Services │ ▼ Domain Data ``` This separates API compatibility concerns from the core application domain. --- # 20. Cross-Cutting Infrastructure Several concerns span multiple Django applications. These are treated as platform infrastructure rather than duplicated inside individual domains. Examples include: | Concern | Primary Component | | --------------------------- | --------------------------- | | Identity | AuthX integration / `users` | | Authorization | `policyengine` | | Auditability | `audit` | | Email | `mailer` | | Async processing | Celery | | Cache / broker | Redis | | Application infrastructure | `core` / `paystream` | | API documentation | `apidocs` | | External service boundaries | `integrations` | Cross-cutting infrastructure should remain independent of individual domain workflows wherever practical. --- # 21. Infrastructure Architecture The current runtime is designed as a conventional Django production stack. ```text Client │ ▼ Nginx │ ▼ Gunicorn │ ▼ Django Application │ ┌─────────────┼─────────────┐ ▼ ▼ ▼ PostgreSQL Redis Celery │ │ │ │ │ ▼ │ │ Background │ │ Workers │ │ └─────────────┴─────────────┘ ``` External services connect through explicit application boundaries. Examples include: ```text DjangoPlay ──► AuthX DjangoPlay ──► SMTP / Email Provider DjangoPlay ──► AI Providers DjangoPlay ──► Cloudflare R2 DjangoPlay ──► Generic Issue Tracker DjangoPlay ──► External APIs ``` --- # 22. Static Assets and CDN Frontend assets are built by the DjangoPlay frontend packaging workflow. Depending on the environment, assets may be served locally or through the Cloudflare R2/CDN path. Conceptually: ```text Frontend Source │ ▼ Asset Build / Packaging │ ├──────────────► Local Static Serving │ └──────────────► Cloudflare R2 │ ▼ CDN ``` The CDN path is an infrastructure concern and does not change the Django application architecture. --- # 23. Dependency Direction DjangoPlay follows a general dependency direction: ```text Presentation │ ▼ Application Services │ ├──────► Policies │ ├──────► Domain Models / Queries │ ├──────► Audit │ ├──────► Tasks │ └──────► Integrations ``` The preferred direction is from application entry points toward reusable application/domain components. Domain modules should avoid unnecessary dependencies on presentation components. For cross-domain communication, application services and explicit integration boundaries are preferred over direct coupling wherever practical. --- # 24. Events and Signals Django signals are used for event-oriented behavior where appropriate. Signals are useful for: * Audit events * Related state updates * Notifications * Event propagation * Background task triggering Signals should remain lightweight. Heavy workflows should be delegated to services or background tasks. Preferred pattern: ```text Signal │ ▼ Service / Task │ ▼ Business Operation ``` Rather than: ```text Signal │ └── Large Business Workflow ``` This keeps event handling predictable and testable. --- # 25. Application Boundary Rules The following architectural rules apply across DjangoPlay. ### Views Views should handle HTTP concerns and delegate application behavior. ### Serializers Serializers should handle request/response representation and validation, not become the primary business-logic layer. ### Services Services own application workflows and business operations. ### Models Models represent domain state and persistence relationships. ### Policies Authorization decisions belong to the policy layer. ### Tasks Long-running or asynchronous work belongs in Celery tasks. ### Integrations External-system communication belongs behind integration boundaries. ### Signals Signals should remain lightweight and delegate substantial work. --- # 26. Architecture Principles DjangoPlay follows these core principles: | Principle | Meaning | | --------------------------- | ------------------------------------------------------------------------------------- | | Modular Monolith | Keep domains modular without premature service decomposition | | Domain Ownership | Each application owns a meaningful responsibility | | Service First | Business workflows live in services | | Thin Presentation | Views and serializers remain focused on transport concerns | | Centralized Authorization | Access decisions use shared policy mechanisms | | Protected Identity Boundary | AuthX remains the external identity authority | | Auditability | Important state changes remain attributable and observable | | Explicit Integrations | External systems are isolated behind integration boundaries | | Async by Design | Long-running work is delegated to Celery | | Reusable Infrastructure | Shared concerns are implemented once where practical | | API Stability | API evolution uses explicit versioning | | Separation of Concerns | Presentation, application, domain and infrastructure responsibilities remain distinct | | Replaceable Dependencies | External providers should not dictate domain architecture | --- # 27. Why Modular Monolith Instead of Microservices? DjangoPlay intentionally does not split every domain into a separate service. A modular monolith provides: * Clear domain boundaries * One deployment unit * Simpler local development * Simpler transactions * Lower operational overhead * Easier debugging * Shared infrastructure * Reusable application services The architecture nevertheless keeps boundaries explicit enough that a future domain can be extracted into a separate service if there is a genuine operational or scaling reason. The goal is therefore: ```text Strong internal boundaries + Simple deployment + Optional future extraction ``` rather than introducing distributed-system complexity prematurely. --- # 28. Evolution and Scalability The architecture supports scaling in several dimensions. ### Application Scaling The Django application can be scaled vertically or horizontally behind a load balancer. ### Worker Scaling Celery workers can be scaled independently from web processes. ### Database Scaling PostgreSQL can be optimized or scaled independently as application demand increases. ### Cache Scaling Redis can be expanded or separated according to workload requirements. ### Integration Scaling External integrations remain isolated so that individual providers can be changed or scaled without restructuring domain applications. The current architecture therefore provides a path from a single-server deployment toward a larger multi-instance deployment without requiring an immediate architectural rewrite. --- # 29. Architecture Summary DjangoPlay is a **modular Django monolith with layered application design**. Its architectural structure can be summarized as: ```text DJANGOPLAY │ ┌─────────┴─────────┐ │ │ Presentation REST APIs │ │ └─────────┬─────────┘ ▼ Service Layer │ ┌────────────────┼────────────────┐ ▼ ▼ ▼ Policies Domain Apps Integrations │ │ │ │ ▼ ▼ │ PostgreSQL External Services │ ├──────────────► Audit │ └──────────────► Celery │ ▼ Redis ``` The resulting architecture keeps DjangoPlay deployable as a single application while maintaining explicit boundaries between: * Identity * Authorization * Domain applications * Business workflows * Persistence * Auditability * Background processing * External integrations * Infrastructure This provides a practical foundation for continued development while preserving a clear path for future scaling and domain extraction.