Project Structure¶
The LMS is organized into four main directories: backend/, frontend/admin/, frontend/borrower/, and docs/.
Top-Level Layout¶
lms/
├── backend/ # Django backend (API, business logic, database)
├── frontend/
│ ├── admin/ # Admin dashboard (react-admin)
│ └── borrower/ # Borrower self-service portal
├── docs/ # MkDocs documentation site
├── docker-compose.yml # Local development services
├── render.yaml # Render.com deployment configuration
└── spec.md # Full system specification
Backend¶
The backend is a Django 5.x project using uv for package management.
Configuration (config/)¶
backend/config/
├── __init__.py
├── asgi.py # ASGI application (uvicorn)
├── celery.py # Celery configuration + TenantTask base class
├── urls.py # URL routing (NinjaExtraAPI at /api/v1/)
└── settings/
├── base.py # Shared settings (apps, middleware, DB, Celery, i18n)
├── development.py # Debug, CORS, console email, eager Celery
├── production.py # Security hardening, external services
└── test.py # Test overrides, in-memory cache, eager Celery
Applications (apps/)¶
22+ Django apps organized by domain. Each app follows the layered architecture convention:
backend/apps/
├── tenants/ # Public schema: tenant + domain models
├── main/ # Main schema: LMS home (admin, allauth)
├── auth/ # Authentication controllers (allauth wrapper)
├── users/ # Custom user model (main + tenant schemas)
├── borrowers/ # Borrower profiles, loan parties, identities, consents
├── programs/ # Lending programs, products, index rates
├── loans/ # Loan records, lifecycle, draws, purchases
├── amortization/ # Amortization schedules + period management
├── payments/ # Payment processing + recurring payments
│ ├── authorizenet/ # Authorize.Net subapp (provider)
│ └── stripe/ # Stripe subapp (provider)
├── fees/ # Fee schedules + fee management
├── servicing/ # Modifications, forbearance, deferments, PTP, payoff, suspense
├── collateral/ # Collateral items, liens, valuations
├── disbursements/ # Loan funding
├── collections/ # Delinquency, queues, dunning, collection actions
├── ledger/ # Double-entry general ledger
├── documents/ # Document storage
│ ├── s3/ # S3 subapp (provider)
│ └── local/ # Local filesystem subapp (provider)
├── portfolio/ # Portfolio management, snapshots, investors
├── reporting/ # Report generation
│ └── providers/ # Report generator implementations
├── compliance/ # Regulatory compliance
│ └── providers/ # Compliance rule implementations
├── communications/ # Templated messaging
│ ├── sendgrid/ # SendGrid subapp (provider)
│ ├── smtp/ # SMTP subapp (provider)
│ └── twilio/ # Twilio subapp (provider)
├── cases/ # Case management, supercases, campaigns
├── operations/ # Event-sourced loan replay
├── providers/ # Provider config + registry
├── tasks/ # Attachable task management
├── notes/ # Attachable notes
├── webhooks/ # Webhook subscriptions + delivery
└── portal/ # Borrower portal backend API (no models)
App Module Convention¶
Each app follows a consistent file layout:
apps/{module}/
├── __init__.py
├── apps.py # Django AppConfig
├── models.py # Data models (fields, constraints, properties)
├── services.py # Business logic (writes, orchestration)
├── selectors.py # Read-only queries (complex querysets)
├── schemas.py # Pydantic schemas (API input/output)
├── api.py # django-ninja-extra controllers (HTTP layer)
├── permissions.py # Custom permission classes (optional)
├── admin.py # Django admin registration (optional)
├── providers/ # Protocol + implementations (optional)
│ ├── __init__.py # Protocol definition + registry
│ └── ... # Provider implementations
├── signals.py # Django signals (optional)
├── tasks.py # Celery tasks (optional)
├── baker_recipes.py # model-bakery test fixture recipes (optional)
├── migrations/
└── tests/
├── test_services.py # Service layer tests (primary focus)
├── test_selectors.py # Selector/query tests
└── test_api.py # API integration tests
See Layered Architecture for how these layers interact.
Common Utilities (common/)¶
Shared utilities used across all apps. This package has no models and no migrations:
| Module | Purpose |
|---|---|
models.py |
Base mixins: UUIDPrimaryKey, Timestamped, ExternalID, Archivable |
schemas.py |
Base Pydantic schemas: BaseModelOut, ArchivableModelOut |
controllers.py |
ReactAdminControllerMixin (pagination, sorting, filtering) |
permissions.py |
RBAC permission classes: IsViewerOrAbove, IsCollectorOrAbove, etc. |
rbac.py |
Role-to-permission mappings, RBAC permission list builder |
validators.py |
Pydantic validators: email, phone, decimal, SSN, content type |
contenttypes.py |
resolve_content_type() for generic FK resolution |
formatting.py |
Locale-aware formatters: fmt_currency, fmt_date, etc. |
pdf.py |
Jinja2 + WeasyPrint PDF rendering with locale-aware filters |
tasks.py |
async_task_delay() for safe Celery dispatch from async code |
selectors.py |
get_audit_history() generic pghistory query |
Test Infrastructure¶
backend/
├── conftest.py # Root conftest (tenant setup, user factories)
└── tests/ # Integration tests (if any)
The root conftest.py provides:
test_tenant--- Session-scoped fixture creating a test tenant + domaintenant_schema--- Autouse fixture activating the test tenant schema for every testuser_factory/user/api_user--- User creation helpers with configurable roles- Connection cleanup fixtures to prevent
ResourceWarningand teardown errors
Frontend (Admin Dashboard)¶
The admin dashboard at frontend/admin/ is a react-admin single-page application:
frontend/admin/src/
├── App.tsx # react-admin <Admin> with all resources
├── main.tsx # Entry point
├── admin/ # Resource screens (50+ directories)
│ ├── Layout.tsx # Admin layout with sidebar
│ ├── Menu.tsx # Permission-gated navigation menu
│ ├── Dashboard.tsx # Dashboard with stats and charts
│ ├── LoginPage.tsx # Login page
│ ├── permissions.ts # hasPermission() utility
│ ├── theme.ts # MUI theme
│ └── {resource}/ # One directory per resource
│ ├── index.ts # Barrel export + icon
│ ├── {Resource}List.tsx
│ ├── {Resource}Show.tsx
│ ├── {Resource}Create.tsx
│ ├── {Resource}Edit.tsx
│ └── __tests__/
├── components/ # Shared components
│ ├── MoneyField.tsx # Currency formatting
│ ├── MoneyInput.tsx # Currency input
│ ├── StatusField.tsx # Status chip
│ ├── PercentField.tsx # Percentage display
│ ├── FullNameField.tsx # First + last name
│ ├── ActionButton.tsx # Action with confirmation dialog
│ └── NestedAuditHistory.tsx
├── providers/
│ ├── dataProvider.ts # Extended data provider (action, getNestedList, createNested)
│ ├── authProvider.ts # Session-based auth
│ └── i18nProvider.ts # English/Spanish
├── utils/
│ └── format.ts # humanize(), formatMoney(), STATUS_COLORS
├── types.ts # TypeScript interfaces + choice constants
└── test-utils.tsx # renderWithAdmin(), renderWithRecord()
Frontend (Borrower Portal)¶
The borrower portal at frontend/borrower/ is a standalone React SPA using MUI and React Query:
frontend/borrower/src/
├── App.tsx # Routes + QueryClient + AuthProvider + ThemeProvider
├── main.tsx # Entry point
├── api/
│ ├── client.ts # HTTP utility (apiFetch, CSRF, ApiHttpError)
│ ├── auth.ts # Session auth (login, logout, getMe)
│ └── portal.ts # Portal API functions (41 functions)
├── contexts/
│ └── AuthContext.tsx # Auth state (borrower, login, logout)
├── hooks/ # React Query hooks (one per domain)
│ ├── usePortalApi.ts # Dashboard and loan queries
│ ├── usePayments.ts # Payment queries and mutations
│ ├── useAutopay.ts # Autopay management
│ ├── useInstruments.ts # Payment instrument management
│ ├── useDocuments.ts # Document queries and upload
│ ├── useProfile.ts # Profile queries and mutations
│ ├── useCases.ts # Support case management
│ ├── useHardship.ts # Hardship applications
│ └── useBranding.ts # Tenant branding query
├── pages/ # 17 page components
├── components/ # 25+ shared components
├── layouts/
│ ├── AuthLayout.tsx # Centered card layout (login, reset)
│ └── PortalLayout.tsx # AppBar + sidebar + main content
├── utils/
│ └── format.ts # Formatting utilities
├── types.ts # TypeScript interfaces
└── test-utils.tsx # Test helpers
Documentation¶
docs/
├── mkdocs.yml # MkDocs configuration (nav, theme, extensions)
├── pyproject.toml # Python deps (mkdocs, mkdocs-material)
└── src/ # Markdown source files
├── index.md # Homepage
├── getting-started/ # Installation, configuration, quick start
├── architecture/ # System design documentation
├── domain/ # Business domain documentation
└── reference/ # Reference tables and enums
Configuration Files¶
| File | Purpose |
|---|---|
backend/pyproject.toml |
Python dependencies (uv) |
frontend/admin/package.json |
Admin dashboard dependencies (npm) |
frontend/borrower/package.json |
Borrower portal dependencies (npm) |
docs/pyproject.toml |
Documentation dependencies (uv) |
docker-compose.yml |
Local development services |
render.yaml |
Render.com deployment configuration |
.github/workflows/ci.yml |
CI/CD pipeline (lint, test, build) |
See Also¶
- Installation --- Setup steps for each component
- Layered Architecture --- How app layers interact
- Architecture Overview --- High-level system design