MAD AI is split across two repositories. The Angular client contains the SSR entry point, routed administrative UI, explicit client-side layers and HTTP adapters. A separate Django REST service owns backend application and persistence concerns. The repositories can evolve independently while meeting at the REST contract.
PROJECT CASE STUDY · FULL-STACK ARCHITECTURE
MAD AI
An administrative web application with an Angular 20 client and a separately maintained private Django 5.2 API, covering authentication, user and role management, notifications and reporting.
SYSTEM BOUNDARY
A public Angular client and a separately maintained private API
PROBLEM
Administrative workflows accumulate cross-cutting concerns quickly
Authentication, guarded navigation, user administration, roles, notifications and reporting all need shared application behavior without turning routed components into transport clients. The project separates those concerns at both ends: an Angular client with explicit layers and a Django REST service with its own application/domain/infrastructure boundaries.
SYSTEM
Two repositories, two independent architectural boundaries
FRONTEND
Layer names correspond to real Angular boundaries
DOMAIN
CONTRACTS BEFORE TRANSPORT
Domain entities and repository abstractions define what authentication, users, roles and notifications need without embedding endpoint details into routed components.
APPLICATION
USE CASES COORDINATE INTENT
Application code sits between presentation and infrastructure so UI flows express actions through use cases instead of binding every component directly to HTTP mechanics.
INFRASTRUCTURE
HTTP REPOSITORIES ADAPT THE API
Concrete implementations for authentication, notifications, roles and users own DTO/API
interaction behind repository contracts. Environment configuration points those adapters
to /api/v1.
PRESENTATION
ROUTES DEFINE PUBLIC AND SECURED AREAS
Authentication routes use their own layout, while dashboard and user-management surfaces
sit behind AuthGuard inside the secured shell. Angular SSR and Express provide the
server-rendered entry path.
BACKEND
The API uses a pragmatic modular Django architecture
The backend uses Django 5.2.3 and Django REST Framework 3.16.0, with JWT/cryptography support, PostgreSQL through psycopg2, filtering, OpenAPI tooling and Celery. Its architecture combines a service layer, domain-centric Django models and ports/adapters rather than forcing a framework-neutral domain that duplicates the ORM.
The API is maintained in a private repository, making the REST contract the explicit boundary between the open client and backend implementation. Presentation and interaction remain client responsibilities; application orchestration and persistence stay behind the API.
REPORTING
The client owns visualization and export concerns
The Angular client includes ECharts, jsPDF and PapaParse. Keeping charting and export libraries in the client lets reporting surfaces transform API responses into interactive visualizations and downloadable representations without pushing presentation concerns back into the REST service.
CURRENT IMPLEMENTATION
Responsibilities remain explicit across client and API
CLIENT
ANGULAR 20 · SSR · EXPRESS 5 · TAILWIND 4
The Angular client uses Angular 20, Angular SSR, Express 5, RxJS and Tailwind CSS 4. Its
code separates domain, application, infrastructure and presentation, with
guarded routes and concrete HTTP repository implementations.
API
DJANGO 5.2 · DRF 3.16 · JWT · POSTGRESQL · CELERY
The companion API uses Django 5.2.3 and DRF 3.16 with JWT/cryptography, PostgreSQL support and Celery. It remains a private service maintained separately from the public client.
ACTIVE BOUNDARY
REQUEST/RESPONSE REST IS THE CURRENT TRANSPORT
The maintained backend does not include Django Channels, so WebSocket behavior is outside the current system flow. Client and API integration is centered on the REST contract.
DELIVERY BOUNDARY
CLIENT AND API CAN EVOLVE INDEPENDENTLY
The split keeps presentation and backend delivery concerns separate. Changes on either side need to preserve the shared REST contract rather than requiring both repositories to share implementation details.
LEARNINGS
What the two-repository design reinforced
LEARNING 01
CLIENT ARCHITECTURE CAN HAVE REAL BOUNDARIES
A frontend can separate domain intent from HTTP adapters instead of treating every component as a wrapper around an endpoint.
LEARNING 02
FRAMEWORK-PRAGMATIC CLEAN BOUNDARIES CAN BE STRONG
Django models can remain rich domain entities while services and repository ports protect orchestration and external adapters; clean architecture does not require fighting the framework.
LEARNING 03
REPOSITORY BOUNDARIES SHOULD MATCH SYSTEM BOUNDARIES
Keeping client contracts separate from backend implementation details reduces coupling between repositories and makes ownership of presentation, transport and persistence responsibilities clearer.