Architecture¶
Technology Stack¶
Backend¶
Django 5.2 — Web framework
Django REST Framework — RESTful API
django-filter — Advanced queryset filtering
mozilla-django-oidc — OpenID Connect authentication
Pillow — Image handling for documents and media
Gunicorn — Production WSGI server
SQLite — Development database
PostgreSQL — Production database
Python 3.11+
Frontend¶
PatternFly 5 — Enterprise UI framework (no build tools; loaded from CDN)
Alpine.js 3 — Lightweight reactive framework (~3KB)
Chart.js 4 — Oil/fuel consumption charts
Font Awesome — Icons
No build pipeline. All JS is vanilla Alpine.js loaded as static files or from CDN.
Deployment¶
Red Hat UBI 9 — Container base image
nginx — Static/media file serving and TLS termination (sidecar)
OpenShift / Kubernetes — Container platform
Project Structure¶
simple-aircraft-manager/
├── simple_aircraft_manager/ # Project configuration
│ ├── settings.py # Development settings (SQLite, DEBUG=True)
│ ├── settings_prod.py # Production settings (requires env vars)
│ ├── urls.py # URL routing
│ └── wsgi.py
├── core/ # Core aircraft management
│ ├── models.py # Aircraft, AircraftNote, AircraftEvent, roles, share tokens
│ ├── views.py # API ViewSets + template views + public sharing
│ ├── serializers.py # DRF serializers
│ ├── permissions.py # RBAC permission classes
│ ├── mixins.py # AircraftScopedMixin, EventLoggingMixin
│ ├── events.py # Event logging (log_event)
│ ├── oidc.py # OIDC backend + logout URL builder
│ ├── context_processors.py # Template context (OIDC_ENABLED)
│ ├── templates/
│ │ ├── base.html # Base template with PatternFly + Alpine.js
│ │ ├── dashboard.html # Fleet dashboard
│ │ ├── aircraft_detail.html # Tabbed aircraft detail page
│ │ └── includes/ # Reusable template partials
│ └── static/
│ ├── css/app.css # Custom styles
│ └── js/ # Alpine.js components (see below)
├── health/ # Maintenance & compliance
│ ├── models.py # Component, Squawk, Logbook, AD, Inspection, etc.
│ ├── views.py # API ViewSets
│ ├── serializers.py # DRF serializers (includes upload validation)
│ ├── services.py # Airworthiness calculation logic
│ └── logbook_import.py # AI-assisted logbook transcription
├── examples/openshift/ # OpenShift deployment manifests
├── Containerfile # Container image definition
├── docker-entrypoint.sh # Container startup script
├── requirements.txt # Development dependencies
└── requirements-prod.txt # Production dependencies
Frontend Architecture (Alpine.js Mixin Pattern)¶
The aircraft detail page is composed from feature mixins merged by mergeMixins() in utils.js:
File |
Function |
Feature |
|---|---|---|
|
|
Component CRUD, tree sorting, status |
|
|
Squawk CRUD, priority helpers |
|
|
Note CRUD |
|
|
Oil record CRUD, consumption chart |
|
|
Fuel record CRUD, burn rate chart |
|
|
Logbook CRUD, file uploads, AI import |
|
|
AD CRUD, compliance records, history |
|
|
Inspection CRUD, history |
|
|
Document/collection CRUD, viewer |
|
|
Major repair/alteration CRUD |
|
|
Recent activity card, history modal |
|
|
Role management, public sharing toggle |
Composer: aircraft-detail.js. Never use {...spread} to merge mixins — it eagerly evaluates get properties. mergeMixins() preserves getter descriptors via Object.getOwnPropertyDescriptors().
Shared utilities in utils.js (loaded globally via base.html): getCookie, mergeMixins, apiRequest, showNotification, formatDate, formatHours, getAirworthinessClass/Text/Tooltip, getSquawkPriorityClass, formatApiError.
Airworthiness Calculation¶
calculate_airworthiness(aircraft) in health/services.py checks in order:
AD compliance
Grounding squawks (priority 0)
Inspection recurrency
Component replacement intervals
Thresholds: overdue → RED; within 10 hours / 30 days → ORANGE.
Content Security Policy¶
All JS must be external files in core/static/js/ — inline <script> blocks are blocked by CSP. CDN allowlist: scripts from cdn.jsdelivr.net, styles from unpkg.com. Adding a new CDN requires updating nginx-config.yaml in the deployment manifests.
Contributing¶
Follow the existing Django app structure (
core/for aircraft-level models,health/for maintenance records)Use UUID primary keys for new models
Add
AircraftScopedMixinandEventLoggingMixinto new ViewSets (seeCLAUDE.md)Run migrations after model changes:
python manage.py makemigrations && python manage.py migrateVerify production settings:
DJANGO_SECRET_KEY=test DJANGO_ALLOWED_HOSTS=localhost python manage.py check --settings=simple_aircraft_manager.settings_prodRegister new models in
admin.pyFor new JS features, create
aircraft-detail-<feature>.jsand add it to the composer and template